mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
rework ca-wiz and add icons to menu for warnings (#2486)
* rework ca-wiz and add icons to menu for warnings * remove root CA button from home page * load fonts before calling complete in setup wiz
This commit is contained in:
@@ -45,18 +45,7 @@ export class SuccessPage {
|
||||
|
||||
async ngAfterViewInit() {
|
||||
this.ngZone.runOutsideAngular(() => this.initMatrix())
|
||||
try {
|
||||
const ret = await this.api.complete()
|
||||
if (!this.isKiosk) {
|
||||
this.torAddress = ret['tor-address']
|
||||
this.lanAddress = ret['lan-address'].replace(/^https:/, 'http:')
|
||||
this.cert = ret['root-ca']
|
||||
|
||||
await this.api.exit()
|
||||
}
|
||||
} catch (e: any) {
|
||||
await this.errCtrl.present(e)
|
||||
}
|
||||
setTimeout(() => this.complete(), 1000)
|
||||
}
|
||||
|
||||
download() {
|
||||
@@ -83,6 +72,21 @@ export class SuccessPage {
|
||||
this.api.exit()
|
||||
}
|
||||
|
||||
private async complete() {
|
||||
try {
|
||||
const ret = await this.api.complete()
|
||||
if (!this.isKiosk) {
|
||||
this.torAddress = ret['tor-address']
|
||||
this.lanAddress = ret['lan-address'].replace(/^https:/, 'http:')
|
||||
this.cert = ret['root-ca']
|
||||
|
||||
await this.api.exit()
|
||||
}
|
||||
} catch (e: any) {
|
||||
await this.errCtrl.present(e)
|
||||
}
|
||||
}
|
||||
|
||||
private initMatrix() {
|
||||
this.ctx = this.canvas.nativeElement.getContext('2d')!
|
||||
this.canvas.nativeElement.width = window.innerWidth
|
||||
|
||||
@@ -22,11 +22,17 @@
|
||||
<ion-label class="label montserrat" routerLinkActive="label_selected">
|
||||
{{ page.title }}
|
||||
</ion-label>
|
||||
<ion-icon
|
||||
*ngIf="page.url === '/system' && (warning$ | async)"
|
||||
color="warning"
|
||||
size="small"
|
||||
name="warning"
|
||||
></ion-icon>
|
||||
<ion-icon
|
||||
*ngIf="page.url === '/system' && (showEOSUpdate$ | async)"
|
||||
color="success"
|
||||
size="small"
|
||||
name="rocket-outline"
|
||||
name="rocket"
|
||||
></ion-icon>
|
||||
<ion-badge
|
||||
*ngIf="page.url === '/updates' && (updateCount$ | async) as updateCount"
|
||||
|
||||
@@ -11,7 +11,9 @@ import {
|
||||
filter,
|
||||
first,
|
||||
map,
|
||||
merge,
|
||||
Observable,
|
||||
of,
|
||||
pairwise,
|
||||
startWith,
|
||||
switchMap,
|
||||
@@ -22,6 +24,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { SplitPaneTracker } from 'src/app/services/split-pane.service'
|
||||
import { Emver, THEME } from '@start9labs/shared'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-menu',
|
||||
@@ -111,6 +114,11 @@ export class MenuComponent {
|
||||
|
||||
readonly theme$ = inject(THEME)
|
||||
|
||||
readonly warning$ = merge(
|
||||
of(this.config.isTorHttp()),
|
||||
this.patch.watch$('server-info', 'ntp-synced').pipe(map(synced => !synced)),
|
||||
)
|
||||
|
||||
constructor(
|
||||
private readonly patch: PatchDB<DataModel>,
|
||||
private readonly eosService: EOSService,
|
||||
@@ -119,5 +127,6 @@ export class MenuComponent {
|
||||
private readonly splitPane: SplitPaneTracker,
|
||||
private readonly emver: Emver,
|
||||
private readonly connectionService: ConnectionService,
|
||||
private readonly config: ConfigService,
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -19,33 +19,35 @@ ion-card {
|
||||
font-family: 'Open Sans';
|
||||
padding: 0.6rem;
|
||||
font-weight: 600;
|
||||
font-size: calc(12px + 0.5vw);
|
||||
height: 3rem;
|
||||
height: 2.4rem;
|
||||
}
|
||||
|
||||
ion-card-content {
|
||||
min-height: 9rem;
|
||||
min-height: 8rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
ion-icon {
|
||||
font-size: calc(90px + 0.5vw);
|
||||
font-size: calc(90px + 0.4vw);
|
||||
--ionicon-stroke-width: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
ion-footer {
|
||||
padding: 1rem;
|
||||
padding: 0 1rem;
|
||||
font-family: 'Open Sans';
|
||||
font-size: clamp(1rem, calc(12px + 0.5vw), 1.3rem);
|
||||
height: 9rem;
|
||||
height: 4.5rem;
|
||||
width: clamp(13rem, 80%, 18rem);
|
||||
margin: 0 auto;
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-md::before {
|
||||
@@ -54,9 +56,6 @@ ion-card {
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
ion-card-title, ion-footer {
|
||||
height: auto !important;
|
||||
}
|
||||
ion-footer {
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
<div #gridContent>
|
||||
<ion-grid>
|
||||
<ion-row class="ion-justify-content-center ion-align-items-center">
|
||||
<ion-col
|
||||
*ngFor="let card of cards"
|
||||
responsiveCol
|
||||
sizeLg="4"
|
||||
sizeSm="6"
|
||||
sizeXs="12"
|
||||
class="ion-align-self-center"
|
||||
>
|
||||
<ion-col *ngFor="let card of cards" sizeXs="12">
|
||||
<widget-card
|
||||
[cardDetails]="card"
|
||||
[containerDimensions]="containerDimensions"
|
||||
|
||||
@@ -3,11 +3,17 @@ ion-col {
|
||||
--ion-grid-column-padding: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1800px) {
|
||||
@media (min-width: 1700px) {
|
||||
div {
|
||||
padding: 0 20%;
|
||||
padding: 0 7%;
|
||||
}
|
||||
ion-col {
|
||||
max-width: 24rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 2000px) {
|
||||
div {
|
||||
padding: 0 12%;
|
||||
}
|
||||
}
|
||||
@@ -38,33 +38,33 @@ export class WidgetListComponent {
|
||||
|
||||
cards: Card[] = [
|
||||
{
|
||||
title: 'Visit the Marketplace',
|
||||
title: 'Server Info',
|
||||
icon: 'information-circle-outline',
|
||||
color: 'var(--alt-green)',
|
||||
description: 'View information about your server',
|
||||
link: '/system/specs',
|
||||
},
|
||||
{
|
||||
title: 'Browse',
|
||||
icon: 'storefront-outline',
|
||||
color: 'var(--alt-blue)',
|
||||
description: 'Shop for your favorite open source services',
|
||||
color: 'var(--alt-purple)',
|
||||
description: 'Browse for services to install',
|
||||
link: '/marketplace',
|
||||
qp: { back: 'true' },
|
||||
},
|
||||
{
|
||||
title: 'Root CA',
|
||||
icon: 'ribbon-outline',
|
||||
color: 'var(--alt-orange)',
|
||||
description: `Download and trust your server's root certificate authority`,
|
||||
link: '/system/root-ca',
|
||||
},
|
||||
{
|
||||
title: 'Create Backup',
|
||||
icon: 'duplicate-outline',
|
||||
color: 'var(--alt-purple)',
|
||||
color: 'var(--alt-blue)',
|
||||
description: 'Back up StartOS and service data',
|
||||
link: '/system/backup',
|
||||
},
|
||||
{
|
||||
title: 'Server Info',
|
||||
icon: 'information-circle-outline',
|
||||
color: 'var(--alt-green)',
|
||||
description: 'View basic information about your server',
|
||||
link: '/system/specs',
|
||||
title: 'Monitor',
|
||||
icon: 'pulse-outline',
|
||||
color: 'var(--alt-orange)',
|
||||
description: `View your system resource usage`,
|
||||
link: '/system/metrics',
|
||||
},
|
||||
{
|
||||
title: 'User Manual',
|
||||
@@ -77,7 +77,7 @@ export class WidgetListComponent {
|
||||
title: 'Contact Support',
|
||||
icon: 'chatbubbles-outline',
|
||||
color: 'var(--alt-red)',
|
||||
description: 'Get help from the Start9 team and community',
|
||||
description: 'Get help from the Start9 community',
|
||||
link: 'https://start9.com/contact',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,106 +1,78 @@
|
||||
<ion-grid class="grid-wiz">
|
||||
<img width="60px" height="60px" src="/assets/img/icon.png" alt="StartOS" />
|
||||
<ion-row>
|
||||
<ion-col class="ion-text-center">
|
||||
<ion-content>
|
||||
<ng-container *ngIf="!caTrusted; else trusted">
|
||||
<ion-icon name="lock-closed-outline" class="wiz-icon"></ion-icon>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col class="ion-text-center">
|
||||
<h2><b>Trust your Root Certificate Authority (CA)</b></h2>
|
||||
<p>
|
||||
Download and trust your server's Root CA to establish secure, encrypted
|
||||
(
|
||||
<h1 class="title">Trust Your Root CA</h1>
|
||||
<p class="subtitle">
|
||||
Download and trust your server's Root Certificate Authority to establish a
|
||||
secure (
|
||||
<b>HTTPS</b>
|
||||
) connections with your server
|
||||
) connection. You will need to repeat this on every device you use to
|
||||
connect to your server.
|
||||
</p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col sizeXs="12" sizeLg="4">
|
||||
<div class="wiz-card">
|
||||
<ion-row class="ion-justify-content-between">
|
||||
<b class="wiz-step">1</b>
|
||||
<tui-tooltip
|
||||
content="Your server uses its Root CA to generate SSL/TLS certificates for itself and its installed services. These certificates are used to encrypt network traffic with your client devices."
|
||||
direction="right"
|
||||
></tui-tooltip>
|
||||
</ion-row>
|
||||
<div class="ion-text-center">
|
||||
<h2>Download Root CA</h2>
|
||||
<p>Download your server's Root CA</p>
|
||||
</div>
|
||||
<ion-button class="wiz-card-button" shape="round" (click)="download()">
|
||||
<ion-icon slot="start" name="download-outline"></ion-icon>
|
||||
<ol>
|
||||
<li>
|
||||
<b>Download your server's Root CA</b>
|
||||
. Your server uses its Root CA to generate SSL/TLS certificates for
|
||||
itself and installed services. These certificates are then used to
|
||||
encrypt network traffic with your client devices.
|
||||
<br />
|
||||
<ion-button strong size="small" (click)="download()">
|
||||
Download
|
||||
<ion-icon slot="end" name="download-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col sizeXs="12" sizeLg="4">
|
||||
<div class="wiz-card" [class.disabled]="!downloadClicked">
|
||||
<ion-row class="ion-justify-content-between">
|
||||
<b class="wiz-step">2</b>
|
||||
<tui-tooltip
|
||||
content="By trusting your server's Root CA, your device can verify the authenticity of its encrypted communications with your server and installed services. You will need to trust the Root CA on every device used to connect to your server."
|
||||
direction="right"
|
||||
></tui-tooltip>
|
||||
</ion-row>
|
||||
<div class="ion-text-center">
|
||||
<h2>Trust Root CA</h2>
|
||||
<p>Follow instructions for your OS</p>
|
||||
</div>
|
||||
<ion-button
|
||||
class="wiz-card-button"
|
||||
shape="round"
|
||||
(click)="instructions()"
|
||||
[disabled]="!downloadClicked"
|
||||
>
|
||||
View Docs
|
||||
</li>
|
||||
<li>
|
||||
<b>Trust your server's Root CA</b>
|
||||
. Follow instructions for your OS. By trusting your server's Root CA,
|
||||
your device can verify the authenticity of encrypted communications with
|
||||
your server.
|
||||
<br />
|
||||
<ion-button strong size="small" (click)="instructions()">
|
||||
View Instructions
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col sizeXs="12" sizeLg="4">
|
||||
<div class="wiz-card" [class.disabled]="!polling && !caTrusted">
|
||||
<b class="wiz-step">3</b>
|
||||
<div class="ion-text-center">
|
||||
<h2>Go To Login</h2>
|
||||
<p *ngIf="instructionsClicked; else space" class="inline-center">
|
||||
<ion-spinner
|
||||
class="wiz-spinner"
|
||||
*ngIf="!caTrusted; else trusted"
|
||||
></ion-spinner>
|
||||
<ng-template #trusted>
|
||||
<ion-icon name="ribbon-outline" color="success"></ion-icon>
|
||||
</ng-template>
|
||||
{{ caTrusted ? 'Root CA trusted!' : 'Waiting for trust...' }}
|
||||
</p>
|
||||
<ng-template #space>
|
||||
<!-- to keep alignment -->
|
||||
<p><br /></p>
|
||||
</ng-template>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<b>Test</b>
|
||||
. If refreshing the page does not work, you may need to quit the browser
|
||||
and re-open.
|
||||
<i>Tip: before quitting, bookmark this page or copy the URL.</i>
|
||||
<br />
|
||||
<ion-button strong size="small" (click)="refresh()">
|
||||
Refresh
|
||||
<ion-icon slot="end" name="refresh"></ion-icon>
|
||||
</ion-button>
|
||||
</li>
|
||||
</ol>
|
||||
<ion-button
|
||||
class="wiz-card-button"
|
||||
shape="round"
|
||||
style="--padding-start: 0"
|
||||
fill="clear"
|
||||
(click)="launchHttps()"
|
||||
[disabled]="!caTrusted"
|
||||
[disabled]="caTrusted"
|
||||
>
|
||||
Open
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col class="ion-text-center">
|
||||
<ion-button fill="clear" (click)="launchHttps()" [disabled]="caTrusted">
|
||||
Skip
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #trusted>
|
||||
<ion-icon
|
||||
name="shield-checkmark-outline"
|
||||
class="wiz-icon"
|
||||
color="success"
|
||||
></ion-icon>
|
||||
<h1 class="title">Root CA Trusted!</h1>
|
||||
<p class="subtitle">
|
||||
You have successfully trusted your server's Root CA and may now log in
|
||||
securely.
|
||||
</p>
|
||||
<ion-button strong (click)="launchHttps()">
|
||||
Go to login
|
||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
|
||||
<a
|
||||
id="install-cert"
|
||||
href="/eos/local.crt"
|
||||
|
||||
@@ -1,44 +1,41 @@
|
||||
.grid-wiz {
|
||||
--ion-grid-padding: 36px;
|
||||
height: 100%
|
||||
ion-content {
|
||||
--padding-top: 2.2rem;
|
||||
--padding-bottom: 2.2rem;
|
||||
--padding-start: 2.2rem;
|
||||
--padding-end: 2.2rem;
|
||||
}
|
||||
|
||||
.wiz-icon {
|
||||
font-size: 84px;
|
||||
}
|
||||
|
||||
.wiz-card {
|
||||
background: #414141;
|
||||
margin: 24px;
|
||||
padding: 16px;
|
||||
height: 280px;
|
||||
border-radius: 16px;
|
||||
display: grid;
|
||||
|
||||
& h2 {
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 21px;
|
||||
line-height: 26px;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ol {
|
||||
font-size: 17px;
|
||||
line-height: 25px;
|
||||
|
||||
li {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
ion-button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.wiz-card-button {
|
||||
justify-self: center;
|
||||
white-space: normal;
|
||||
a {
|
||||
cursor: pointer;
|
||||
color: aquamarine;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.wiz-spinner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
filter: saturate(0.2) contrast(0.5)
|
||||
}
|
||||
|
||||
.wiz-step {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.inline-center {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
.wiz-icon {
|
||||
font-size: 64px;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, Inject } from '@angular/core'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { pauseFor, RELATIVE_URL } from '@start9labs/shared'
|
||||
import { RELATIVE_URL } from '@start9labs/shared'
|
||||
import { DOCUMENT } from '@angular/common'
|
||||
import { WINDOW } from '@ng-web-apis/common'
|
||||
|
||||
@@ -11,9 +11,6 @@ import { WINDOW } from '@ng-web-apis/common'
|
||||
styleUrls: ['./ca-wizard.component.scss'],
|
||||
})
|
||||
export class CAWizardComponent {
|
||||
downloadClicked = false
|
||||
instructionsClicked = false
|
||||
polling = false
|
||||
caTrusted = false
|
||||
|
||||
constructor(
|
||||
@@ -25,15 +22,12 @@ export class CAWizardComponent {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
if (!this.config.isSecure()) {
|
||||
await this.testHttps().catch(e =>
|
||||
console.warn('Failed Https connection attempt'),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
download() {
|
||||
this.downloadClicked = true
|
||||
this.document.getElementById('install-cert')?.click()
|
||||
}
|
||||
|
||||
@@ -43,21 +37,10 @@ export class CAWizardComponent {
|
||||
'_blank',
|
||||
'noreferrer',
|
||||
)
|
||||
this.instructionsClicked = true
|
||||
this.startDaemon()
|
||||
}
|
||||
|
||||
private async startDaemon(): Promise<void> {
|
||||
this.polling = true
|
||||
while (this.polling) {
|
||||
try {
|
||||
await this.testHttps()
|
||||
this.polling = false
|
||||
} catch (e) {
|
||||
console.warn('Failed Https connection attempt')
|
||||
await pauseFor(2000)
|
||||
}
|
||||
}
|
||||
refresh() {
|
||||
this.document.location.reload()
|
||||
}
|
||||
|
||||
launchHttps() {
|
||||
@@ -68,8 +51,6 @@ export class CAWizardComponent {
|
||||
private async testHttps() {
|
||||
const url = `https://${this.document.location.host}${this.relativeUrl}`
|
||||
await this.api.echo({ message: 'ping' }, url).then(() => {
|
||||
this.downloadClicked = true
|
||||
this.instructionsClicked = true
|
||||
this.caTrusted = true
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user