mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
remove product key from setup flow (#1750)
* remove product key flow from setup * feat: backend turned off encryption + new Id + no package id * implement new encryption scheme in FE * decode response string * crypto not working * update setup wizard closes #1762 * feat: Get the encryption key * fix: Get to recovery * remove old code * fix build * fix: Install works for now * fix bug in config for adding new list items * dismiss action modal on success * clear button in config * wip: Currently broken in avahi mdns * include headers with req/res and refactor patchDB init and usage * fix: Can now run in the main * flatline on failed init * update patch DB * add last-wifi-region to data model even though not used by FE * chore: Fix the start. * wip: Fix wrong order for getting hostname before sql has been created * fix edge case where union keys displayed as new when not new * fix: Can start * last backup color, markdown links always new tab, fix bug with login * refactor to remove WithRevision * resolve circular dep issue * update submodule * fix patch-db * update patchDB * update patch again * escape error * decodeuricomponent * increase proxy buffer size * increase proxy buffer size * fix nginx Co-authored-by: BluJ <mogulslayer@gmail.com> Co-authored-by: BluJ <dragondef@gmail.com> Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
import { RpcErrorDetails } from '../types/rpc-error-details'
|
||||
import { RPCErrorDetails } from '../types/rpc.types'
|
||||
|
||||
export class RpcError<T> {
|
||||
export class RpcError {
|
||||
readonly code = this.error.code
|
||||
readonly message = this.getMessage()
|
||||
readonly revision = this.getRevision()
|
||||
|
||||
constructor(private readonly error: RpcErrorDetails<T>) {}
|
||||
constructor(private readonly error: RPCErrorDetails) {}
|
||||
|
||||
private getMessage(): string {
|
||||
if (typeof this.error.data === 'string') {
|
||||
@@ -16,10 +15,4 @@ export class RpcError<T> {
|
||||
? `${this.error.message}\n\n${this.error.data.details}`
|
||||
: this.error.message
|
||||
}
|
||||
|
||||
private getRevision(): T | null {
|
||||
return typeof this.error.data === 'string'
|
||||
? null
|
||||
: this.error.data?.revision || null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,17 +14,15 @@ export class MarkdownComponent {
|
||||
@Input() content!: string | Observable<string>
|
||||
@Input() title!: string
|
||||
|
||||
private readonly data$ = defer(() =>
|
||||
readonly content$ = defer(() =>
|
||||
isObservable(this.content) ? this.content : of(this.content),
|
||||
).pipe(share())
|
||||
|
||||
readonly error$ = this.data$.pipe(
|
||||
readonly error$ = this.content$.pipe(
|
||||
ignoreElements(),
|
||||
catchError(e => of(getErrorMessage(e))),
|
||||
)
|
||||
|
||||
readonly content$ = this.data$.pipe(catchError(() => of([])))
|
||||
|
||||
constructor(private readonly modalCtrl: ModalController) {}
|
||||
|
||||
async dismiss() {
|
||||
|
||||
@@ -6,11 +6,22 @@ import * as DOMPurify from 'dompurify'
|
||||
name: 'markdown',
|
||||
})
|
||||
export class MarkdownPipe implements PipeTransform {
|
||||
transform(value: any): any {
|
||||
transform(value: string): string {
|
||||
if (value && value.length > 0) {
|
||||
// convert markdown to html
|
||||
const html = marked(value)
|
||||
// sanitize html
|
||||
const sanitized = DOMPurify.sanitize(html)
|
||||
return sanitized
|
||||
// parse html to find all links
|
||||
let parser = new DOMParser()
|
||||
const doc = parser.parseFromString(sanitized, 'text/html')
|
||||
const links = Array.from(doc.getElementsByTagName('a'))
|
||||
// add target="_blank" to every link
|
||||
links.forEach(link => {
|
||||
link.setAttribute('target', '_blank')
|
||||
})
|
||||
// return new html string
|
||||
return doc.documentElement.innerHTML
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -40,12 +40,14 @@ export * from './services/error-toast.service'
|
||||
export * from './services/http.service'
|
||||
|
||||
export * from './types/api'
|
||||
export * from './types/rpc-error-details'
|
||||
export * from './types/http.types'
|
||||
export * from './types/rpc.types'
|
||||
export * from './types/url'
|
||||
export * from './types/workspace-config'
|
||||
|
||||
export * from './util/copy-to-clipboard'
|
||||
export * from './util/get-pkg-id'
|
||||
export * from './util/misc.util'
|
||||
export * from './util/rpc.util'
|
||||
export * from './util/to-local-iso-string'
|
||||
export * from './util/unused'
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||
import { HttpError, RpcError, WorkspaceConfig } from '@start9labs/shared'
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { HttpError } from '../classes/http-error'
|
||||
import {
|
||||
HttpAngularOptions,
|
||||
HttpOptions,
|
||||
LocalHttpResponse,
|
||||
Method,
|
||||
} from '../types/http.types'
|
||||
import { RPCResponse, RPCOptions } from '../types/rpc.types'
|
||||
import { WorkspaceConfig } from '../types/workspace-config'
|
||||
import {
|
||||
firstValueFrom,
|
||||
from,
|
||||
@@ -32,20 +40,21 @@ export class HttpService {
|
||||
this.fullUrl = `${protocol}//${hostname}:${port}`
|
||||
}
|
||||
|
||||
async rpcRequest<T>(opts: RPCOptions): Promise<T> {
|
||||
const { method, params, timeout } = opts
|
||||
async rpcRequest<T>(
|
||||
opts: RPCOptions,
|
||||
): Promise<LocalHttpResponse<RPCResponse<T>>> {
|
||||
const { method, headers, params, timeout } = opts
|
||||
|
||||
const res = await this.httpRequest<RPCResponse<T>>({
|
||||
return this.httpRequest<RPCResponse<T>>({
|
||||
method: Method.POST,
|
||||
url: this.relativeUrl,
|
||||
headers,
|
||||
body: { method, params },
|
||||
timeout,
|
||||
})
|
||||
if (isRpcError(res)) throw new RpcError(res.error)
|
||||
return res.result
|
||||
}
|
||||
|
||||
async httpRequest<T>(opts: HttpOptions): Promise<T> {
|
||||
async httpRequest<T>(opts: HttpOptions): Promise<LocalHttpResponse<T>> {
|
||||
let { method, url, headers, body, responseType, timeout } = opts
|
||||
|
||||
url = opts.url.startsWith('/') ? this.fullUrl + url : url
|
||||
@@ -67,113 +76,21 @@ export class HttpService {
|
||||
responseType: responseType || 'json',
|
||||
}
|
||||
|
||||
let req: Observable<{ body: T }>
|
||||
let req: Observable<LocalHttpResponse<T>>
|
||||
if (method === Method.GET) {
|
||||
req = this.http.get(url, options as any) as any
|
||||
} else {
|
||||
req = this.http.post(url, body, options as any) as any
|
||||
}
|
||||
|
||||
return firstValueFrom(timeout ? withTimeout(req, timeout) : req)
|
||||
.then(res => res.body)
|
||||
.catch(e => {
|
||||
return firstValueFrom(timeout ? withTimeout(req, timeout) : req).catch(
|
||||
e => {
|
||||
throw new HttpError(e)
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ** RPC types **
|
||||
|
||||
interface RPCBase {
|
||||
jsonrpc: '2.0'
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface RPCRequest<T> extends RPCBase {
|
||||
method: string
|
||||
params?: T
|
||||
}
|
||||
|
||||
export interface RPCSuccess<T> extends RPCBase {
|
||||
result: T
|
||||
}
|
||||
|
||||
export interface RPCError extends RPCBase {
|
||||
error: {
|
||||
code: number
|
||||
message: string
|
||||
data?:
|
||||
| {
|
||||
details: string
|
||||
}
|
||||
| string
|
||||
}
|
||||
}
|
||||
|
||||
export type RPCResponse<T> = RPCSuccess<T> | RPCError
|
||||
|
||||
export interface RPCOptions {
|
||||
method: string
|
||||
params: {
|
||||
[param: string]:
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| object
|
||||
| string[]
|
||||
| number[]
|
||||
| null
|
||||
}
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
export function isRpcError<Error, Result>(
|
||||
arg: { error: Error } | { result: Result },
|
||||
): arg is { error: Error } {
|
||||
return (arg as any).error !== undefined
|
||||
}
|
||||
|
||||
// ** HTTP types **
|
||||
|
||||
export enum Method {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
}
|
||||
|
||||
export interface HttpOptions {
|
||||
method: Method
|
||||
url: string
|
||||
headers?:
|
||||
| HttpHeaders
|
||||
| {
|
||||
[header: string]: string | string[]
|
||||
}
|
||||
params?:
|
||||
| HttpParams
|
||||
| {
|
||||
[param: string]: string | string[]
|
||||
}
|
||||
responseType?: 'json' | 'text' | 'arrayBuffer'
|
||||
body?: any
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
interface HttpAngularOptions {
|
||||
observe: 'response'
|
||||
withCredentials: true
|
||||
headers?:
|
||||
| HttpHeaders
|
||||
| {
|
||||
[header: string]: string | string[]
|
||||
}
|
||||
params?:
|
||||
| HttpParams
|
||||
| {
|
||||
[param: string]: string | string[]
|
||||
}
|
||||
responseType?: 'json' | 'text' | 'arrayBuffer'
|
||||
}
|
||||
|
||||
function hasParams(
|
||||
params?: HttpOptions['params'],
|
||||
): params is Record<string, string | string[]> {
|
||||
@@ -191,9 +108,3 @@ function withTimeout<U>(req: Observable<U>, timeout: number): Observable<U> {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export interface RequestError {
|
||||
code: number
|
||||
message: string
|
||||
details: string
|
||||
}
|
||||
|
||||
44
frontend/projects/shared/src/types/http.types.ts
Normal file
44
frontend/projects/shared/src/types/http.types.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { HttpHeaders, HttpResponse } from '@angular/common/http'
|
||||
|
||||
export enum Method {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
}
|
||||
|
||||
export interface HttpOptions {
|
||||
method: Method
|
||||
url: string
|
||||
headers?: {
|
||||
[header: string]: string | string[]
|
||||
}
|
||||
params?: {
|
||||
[param: string]: string | string[]
|
||||
}
|
||||
responseType?: 'json' | 'text' | 'arrayBuffer'
|
||||
body?: any
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
export interface HttpAngularOptions {
|
||||
observe: 'response'
|
||||
withCredentials: true
|
||||
headers?:
|
||||
| HttpHeaders
|
||||
| {
|
||||
[header: string]: string | string[]
|
||||
}
|
||||
params?: {
|
||||
[param: string]: string | string[]
|
||||
}
|
||||
responseType?: 'json' | 'text' | 'arrayBuffer'
|
||||
}
|
||||
|
||||
export interface LocalHttpResponse<T> extends HttpResponse<T> {
|
||||
body: T
|
||||
}
|
||||
|
||||
export interface RequestError {
|
||||
code: number
|
||||
message: string
|
||||
details: string
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export interface RpcErrorDetails<T> {
|
||||
code: number
|
||||
message: string
|
||||
data?:
|
||||
| {
|
||||
details: string
|
||||
revision?: T | null
|
||||
}
|
||||
| string
|
||||
}
|
||||
55
frontend/projects/shared/src/types/rpc.types.ts
Normal file
55
frontend/projects/shared/src/types/rpc.types.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
// ** RPC types **
|
||||
|
||||
interface RPCBase {
|
||||
jsonrpc: '2.0'
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface RPCRequest<T> extends RPCBase {
|
||||
method: string
|
||||
params?: T
|
||||
}
|
||||
|
||||
export interface RPCSuccessRes<T> extends RPCBase {
|
||||
result: T
|
||||
}
|
||||
|
||||
export interface RPCErrorRes extends RPCBase {
|
||||
error: RPCErrorDetails
|
||||
}
|
||||
|
||||
export interface RPCErrorDetails {
|
||||
code: number
|
||||
message: string
|
||||
data?:
|
||||
| {
|
||||
details: string
|
||||
}
|
||||
| string
|
||||
}
|
||||
|
||||
export type RPCResponse<T> = RPCSuccessRes<T> | RPCErrorRes
|
||||
|
||||
export interface RPCOptions {
|
||||
method: string
|
||||
headers?: {
|
||||
[header: string]: string | string[]
|
||||
}
|
||||
params: {
|
||||
[param: string]:
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| object
|
||||
| string[]
|
||||
| number[]
|
||||
| null
|
||||
}
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
export function isRpcError<Error, Result>(
|
||||
arg: { error: Error } | { result: Result },
|
||||
): arg is { error: Error } {
|
||||
return (arg as any).error !== undefined
|
||||
}
|
||||
11
frontend/projects/shared/src/util/rpc.util.ts
Normal file
11
frontend/projects/shared/src/util/rpc.util.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { RPCErrorDetails } from '../types/rpc.types'
|
||||
|
||||
export function getRpcErrorMessage(error: RPCErrorDetails): string {
|
||||
if (typeof error.data === 'string') {
|
||||
return `${error.message}\n\n${error.data}`
|
||||
}
|
||||
|
||||
return error.data?.details
|
||||
? `${error.message}\n\n${error.data.details}`
|
||||
: error.message
|
||||
}
|
||||
@@ -24,3 +24,6 @@
|
||||
@import "~@ionic/angular/css/text-alignment.css";
|
||||
@import "~@ionic/angular/css/text-transformation.css";
|
||||
@import "~@ionic/angular/css/flex-utils.css";
|
||||
|
||||
/* Import swiper styles for slides */
|
||||
@import '~swiper/scss';
|
||||
|
||||
@@ -18,6 +18,12 @@ ion-alert {
|
||||
}
|
||||
}
|
||||
|
||||
.swiper {
|
||||
.swiper-slide {
|
||||
display: unset;
|
||||
}
|
||||
}
|
||||
|
||||
ion-modal::part(content) {
|
||||
position: absolute;
|
||||
height: 90% !important;
|
||||
|
||||
Reference in New Issue
Block a user