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:
Matt Hill
2022-09-07 09:25:01 -06:00
committed by GitHub
parent 76682ebef0
commit 50111e37da
175 changed files with 11436 additions and 2906 deletions

View File

@@ -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
}
}

View File

@@ -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() {

View File

@@ -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
}

View File

@@ -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'

View File

@@ -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
}

View 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
}

View File

@@ -1,10 +0,0 @@
export interface RpcErrorDetails<T> {
code: number
message: string
data?:
| {
details: string
revision?: T | null
}
| string
}

View 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
}

View 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
}

View File

@@ -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';

View File

@@ -18,6 +18,12 @@ ion-alert {
}
}
.swiper {
.swiper-slide {
display: unset;
}
}
ion-modal::part(content) {
position: absolute;
height: 90% !important;