security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed): - CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed - HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted - HIGH: tar slip prevention, S3 SSRF validation, backup ID validation - MEDIUM: remember-me random secret, TOTP session rotation, password re-auth - LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation Container reliability: - Memory limits on all 37 containers (OOM prevention) - Exited vs stopped state distinction with health-aware status badges - Crash recovery coordination (no more restart cascade) - User-stopped tracking survives reboots - Tiered boot recovery (databases → core → services → apps) UI: - Wallet TransactionsModal, health-aware app status badges - Restart button on containers, exited/crashed red state - Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch - Apps sticky header removed, dev faucet, mutable mock wallet Infrastructure: - LND REST port 8080 exposed over Tor (LND Connect fix) - Nginx cookie_session fix, deploy script Tor config updated - Dev environment: podman auto-start, boot mode simulation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,7 @@
|
||||
|
||||
/* Mobile touch targets — ensure tappable elements meet 44px minimum */
|
||||
@media (max-width: 767px) {
|
||||
button:not(.mode-switcher-btn):not(.sidebar-nav-item):not([class*="w-9"]):not([class*="w-8"]):not([class*="w-7"]) {
|
||||
button:not(.mode-switcher-btn):not(.sidebar-nav-item):not([class*="w-9"]):not([class*="w-8"]):not([class*="w-7"]):not([class*="w-10"]):not([class*="w-11"]):not([class*="w-12"]) {
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,6 @@ button:active:not(:disabled),
|
||||
[role="button"]:active,
|
||||
a.glass-card:active,
|
||||
a.goal-card:active,
|
||||
.info-card-button:active,
|
||||
.path-action-button:active {
|
||||
transform: scale(0.97) !important;
|
||||
transition: transform 0.1s ease !important;
|
||||
@@ -244,18 +243,21 @@ input[type="radio"]:active + * {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* On mobile browsers, cap chat height to the dynamic viewport to prevent
|
||||
content extending behind browser chrome (address bar / toolbar). */
|
||||
@media (max-width: 767px) {
|
||||
.chat-fullscreen {
|
||||
max-height: 100vh;
|
||||
max-height: 100dvh;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-mode-pill {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 2.25rem;
|
||||
right: 1.25rem;
|
||||
z-index: 10;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.chat-mode-pill {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-iframe {
|
||||
flex: 1;
|
||||
@@ -265,10 +267,15 @@ input[type="radio"]:active + * {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* On mobile, shrink iframe height so AIUI ends above the Archipelago tab bar */
|
||||
/* On mobile, shrink iframe height so AIUI ends above the Archipelago tab bar.
|
||||
Use dvh (dynamic viewport height) instead of 100% — on a normal mobile browser,
|
||||
100% resolves through the parent chain to the large viewport (100vh) which
|
||||
is taller than the visible area when the browser chrome is showing. dvh
|
||||
tracks the actual visible viewport. */
|
||||
@media (max-width: 767px) {
|
||||
.chat-iframe-mobile {
|
||||
height: calc(100% - var(--mobile-tab-bar-height, 72px)) !important;
|
||||
height: calc(100vh - var(--mobile-tab-bar-height, 72px)) !important;
|
||||
height: calc(100dvh - var(--mobile-tab-bar-height, 72px)) !important;
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
@@ -441,6 +448,112 @@ input[type="radio"]:active + * {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
/* Glass button color variants */
|
||||
.glass-button-warning {
|
||||
background: rgba(251, 146, 60, 0.2);
|
||||
border: 1px solid rgba(251, 146, 60, 0.3);
|
||||
color: #fdba74;
|
||||
}
|
||||
|
||||
.glass-button-warning:hover {
|
||||
background: rgba(251, 146, 60, 0.3);
|
||||
}
|
||||
|
||||
.glass-button-danger {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.glass-button-danger:hover {
|
||||
background: rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.glass-button-success {
|
||||
background: rgba(74, 222, 128, 0.2);
|
||||
border: 1px solid rgba(74, 222, 128, 0.4);
|
||||
color: #bbf7d0;
|
||||
}
|
||||
|
||||
.glass-button-success:hover {
|
||||
background: rgba(74, 222, 128, 0.3);
|
||||
}
|
||||
|
||||
/* Status badges — inline colored pills */
|
||||
.status-success {
|
||||
background: rgba(74, 222, 128, 0.2);
|
||||
color: #4ade80;
|
||||
}
|
||||
|
||||
.status-error {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
.status-warning {
|
||||
background: rgba(251, 146, 60, 0.2);
|
||||
color: #fb923c;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
/* Alert banners — padded containers with border */
|
||||
.alert-success {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(74, 222, 128, 0.1);
|
||||
border: 1px solid rgba(74, 222, 128, 0.2);
|
||||
border-radius: 0.5rem;
|
||||
color: #bbf7d0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||
border-radius: 0.5rem;
|
||||
color: #fca5a5;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(251, 146, 60, 0.1);
|
||||
border: 1px solid rgba(251, 146, 60, 0.2);
|
||||
border-radius: 0.5rem;
|
||||
color: #fdba74;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
border: 1px solid rgba(59, 130, 246, 0.2);
|
||||
border-radius: 0.5rem;
|
||||
color: #93c5fd;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Form input focus ring */
|
||||
.input-glass {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 0.875rem;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.input-glass:focus {
|
||||
outline: none;
|
||||
border-color: #fb923c;
|
||||
box-shadow: 0 0 0 1px #fb923c;
|
||||
}
|
||||
|
||||
/* Toast - glassmorphic, top-right */
|
||||
.toast-glass {
|
||||
background-color: rgba(0, 0, 0, 0.65);
|
||||
@@ -593,22 +706,6 @@ input[type="radio"]:active + * {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Gradient border container for large content areas */
|
||||
.gradient-border-container {
|
||||
position: relative;
|
||||
border-radius: 1.5rem;
|
||||
padding: 4px;
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(0, 0, 0, 0.6) 100%);
|
||||
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.gradient-border-container-inner {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
border-radius: 1.25rem;
|
||||
}
|
||||
|
||||
/* Choose Your Path - Main Container */
|
||||
.path-glass-container {
|
||||
width: calc(100% - 48px);
|
||||
@@ -876,6 +973,28 @@ input[type="radio"]:active + * {
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal transition (Vue <Transition name="modal">) — shared across all modal components */
|
||||
.modal-enter-active,
|
||||
.modal-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-enter-active .glass-card,
|
||||
.modal-leave-active .glass-card {
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-enter-from,
|
||||
.modal-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.modal-enter-from .glass-card,
|
||||
.modal-leave-to .glass-card {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Background image */
|
||||
body {
|
||||
margin: 0;
|
||||
@@ -958,10 +1077,10 @@ iframe.iframe-scrollbar-hide {
|
||||
}
|
||||
|
||||
@keyframes caretBlink {
|
||||
0%, 100% {
|
||||
border-right-color: #00ffff;
|
||||
0%, 100% {
|
||||
border-right-color: #fbbf24;
|
||||
}
|
||||
50% {
|
||||
50% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
@@ -999,15 +1118,6 @@ iframe.iframe-scrollbar-hide {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes caretBlink {
|
||||
0%, 100% {
|
||||
border-right-color: #fbbf24;
|
||||
}
|
||||
50% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Splash screen styles */
|
||||
.splash-complete .login-card {
|
||||
animation: fadeUpIn 900ms cubic-bezier(0.22, 1, 0.36, 1) 120ms both;
|
||||
@@ -1065,9 +1175,9 @@ body::after {
|
||||
animation-fill-mode: backwards;
|
||||
}
|
||||
|
||||
/* Dashboard: full viewport width, no letterboxing */
|
||||
/* Dashboard: full viewport width, no letterboxing, no body scroll */
|
||||
body.dashboard-active {
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1590,46 +1700,6 @@ html:has(body.video-background-active)::before {
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
/* Toggle switch */
|
||||
.share-toggle {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 2.75rem;
|
||||
height: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.share-toggle input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.share-toggle-slider {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 9999px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
.share-toggle-slider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
left: 0.1875rem;
|
||||
bottom: 0.1875rem;
|
||||
border-radius: 9999px;
|
||||
background: white;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.share-toggle input:checked + .share-toggle-slider {
|
||||
background: #fb923c;
|
||||
}
|
||||
.share-toggle input:checked + .share-toggle-slider::before {
|
||||
transform: translateX(1.25rem);
|
||||
}
|
||||
|
||||
/* Access type options */
|
||||
.share-access-options {
|
||||
display: grid;
|
||||
@@ -1823,44 +1893,6 @@ html:has(body.video-background-active)::before {
|
||||
.monitoring-bar-danger {
|
||||
background: #ef4444;
|
||||
}
|
||||
.monitoring-alert-toggle {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.monitoring-alert-toggle input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.monitoring-alert-toggle-slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
inset: 0;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
.monitoring-alert-toggle-slider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.monitoring-alert-toggle input:checked + .monitoring-alert-toggle-slider {
|
||||
background: rgba(74, 222, 128, 0.4);
|
||||
}
|
||||
.monitoring-alert-toggle input:checked + .monitoring-alert-toggle-slider::before {
|
||||
transform: translateX(16px);
|
||||
background: #4ade80;
|
||||
}
|
||||
.monitoring-threshold-input {
|
||||
width: 60px;
|
||||
padding: 4px 8px;
|
||||
@@ -1872,42 +1904,3 @@ html:has(body.video-background-active)::before {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Toggle switch for Tor services and similar on/off controls */
|
||||
.tor-toggle-label {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tor-toggle-input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
}
|
||||
.tor-toggle-slider {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
.tor-toggle-slider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
transition: transform 0.3s ease, background 0.3s ease;
|
||||
}
|
||||
.tor-toggle-input:checked + .tor-toggle-slider {
|
||||
background: rgba(251, 146, 60, 0.4);
|
||||
}
|
||||
.tor-toggle-input:checked + .tor-toggle-slider::before {
|
||||
transform: translateX(16px);
|
||||
background: #fb923c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user