0.3.0 refactor

ui: adds overlay layer to patch-db-client

ui: getting towards mocks

ui: cleans up factory init

ui: nice type hack

ui: live api for patch

ui: api service source + http

starts up

ui: api source + http

ui: rework patchdb config, pass stashTimeout into patchDbModel

wires in temp patching into api service

ui: example of wiring patchdbmodel into page

begin integration

remove unnecessary method

linting

first data rendering

rework app initialization

http source working for ssh delete call

temp patches working

entire Embassy tab complete

not in kansas anymore

ripping, saving progress

progress for API request response types and endoint defs

Update data-model.ts

shambles, but in a good way

progress

big progress

progress

installed list working

big progress

progress

progress

begin marketplace redesign

Update api-types.ts

Update api-types.ts

marketplace improvements

cosmetic

dependencies and recommendations

begin nym auth approach

install wizard

restore flow and donations
This commit is contained in:
Aaron Greenspan
2021-02-16 13:45:09 -07:00
committed by Aiden McClelland
parent 46f32cb90b
commit 8d01ebe8b2
238 changed files with 25509 additions and 14852 deletions

View File

@@ -2,124 +2,108 @@ import { Injectable } from '@angular/core'
import { ModalController } from '@ionic/angular'
import { AppConfigValuePage } from '../modals/app-config-value/app-config-value.page'
import { ApiService } from './api/api.service'
import { PropertySubject } from '../util/property-subject.util'
import { S9Server, ServerModel } from '../models/server-model'
import { ValueSpec } from '../app-config/config-types'
import { ConfigSpec } from '../pkg-config/config-types'
import { ConfigCursor } from '../pkg-config/config-cursor'
import { SSHService } from '../pages/server-routes/developer-routes/dev-ssh-keys/ssh.service'
@Injectable({
providedIn: 'root',
})
export class ServerConfigService {
server: PropertySubject<S9Server>
constructor (
private readonly modalCtrl: ModalController,
private readonly apiService: ApiService,
private readonly serverModel: ServerModel,
) {
this.server = this.serverModel.watch()
}
private readonly sshService: SSHService,
) { }
async presentModalValueEdit (key: string, current?: string) {
const cursor = new ConfigCursor(serverConfig, { [key]: current }).seekNext(key)
async presentModalValueEdit (key: string, add = false) {
const modal = await this.modalCtrl.create({
backdropDismiss: false,
component: AppConfigValuePage,
presentingElement: await this.modalCtrl.getTop(),
componentProps: {
...this.getConfigSpec(key),
value: add ? '' : this.server[key].getValue(),
cursor,
saveFn: this.saveFns[key],
},
})
await modal.present()
}
private getConfigSpec (key: string): SpecAndSaveFn {
const configSpec: { [key: string]: SpecAndSaveFn } = {
name: {
spec: {
type: 'string',
name: 'Device Name',
description: 'A unique label for this device.',
nullable: false,
// @TODO determine regex
// pattern: '',
patternDescription: 'Must be less than 40 characters',
masked: false,
copyable: true,
},
saveFn: (val: string) => {
return this.apiService.patchServerConfig('name', val).then(() => this.serverModel.update({ name: val }))
},
},
autoCheckUpdates: {
spec: {
type: 'boolean',
name: 'Auto Check for Updates',
description: 'On launch, EmabssyOS will automatically check for updates of itself and your installed services. Updating still requires user approval and action. No updates will ever be performed automatically.',
default: true,
},
saveFn: (val: boolean) => {
return this.apiService.patchServerConfig('autoCheckUpdates', val).then(() => this.serverModel.update({ autoCheckUpdates: val }))
},
},
// password: {
// spec: {
// type: 'string',
// name: 'Change Password',
// description: 'The master password for your Embassy. Must contain at least 128 bits of entropy.',
// nullable: false,
// // @TODO figure out how to confirm min entropy
// // pattern: '^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[*.!@#$%^&*\]).{12,32}$',
// patternDescription: 'Password too simple. Password must contain at least 128 bits of entroy.',
// changeWarning: 'Changing your password will have no affect on old backups. In order to restore old backups, you must provide the password that was used to create them.',
// masked: true,
// copyable: true,
// },
// saveFn: (val: string) => {
// return this.apiService.patchServerConfig('password', val)
// },
// },
// alternativeRegistryUrl: {
// spec: {
// type: 'string',
// name: 'Marketplace URL',
// description: 'Used for connecting to an alternative service marketplace.',
// nullable: true,
// // @TODO regex for URL
// // pattern: '',
// patternDescription: 'Must be a valid URL',
// changeWarning: 'Downloading services from an alternative marketplace could result in malicious or harmful code being installed on your device.',
// masked: false,
// copyable: true,
// },
// saveFn: (val: string) => {
// return this.apiService.patchServerConfig('alternativeRegistryUrl', val).then(() => this.serverModel.update({ alternativeRegistryUrl: val }))
// },
// },
ssh: {
spec: {
type: 'string',
name: 'SSH Key',
description: 'Add SSH keys to your Embassy to gain root access from the command line.',
nullable: false,
// @TODO regex for SSH Key
// pattern: '',
patternDescription: 'Must be a valid SSH key',
masked: true,
copyable: true,
},
saveFn: (val: string) => {
return this.apiService.addSSHKey(val)
},
},
}
return configSpec[key]
saveFns: { [key: string]: (val: any) => Promise<any> } = {
name: async (value: string) => {
return this.apiService.setDbValue({ pointer: 'ui/name', value })
},
autoCheckUpdates: async (value: boolean) => {
return this.apiService.setDbValue({ pointer: 'ui/auto-check-updates', value })
},
ssh: async (pubkey: string) => {
return this.sshService.add(pubkey)
},
registry: async (url: string) => {
return this.apiService.setRegistry({ url })
},
// password: async (password: string) => {
// return this.apiService.updatePassword({ password })
// },
}
}
interface SpecAndSaveFn {
spec: ValueSpec
saveFn: (val: any) => Promise<any>
const serverConfig: ConfigSpec = {
name: {
type: 'string',
name: 'Device Name',
description: 'A unique label for this device.',
nullable: false,
// @TODO determine regex
// pattern: '',
patternDescription: 'Must be less than 40 characters',
masked: false,
copyable: false,
},
autoCheckUpdates: {
type: 'boolean',
name: 'Auto Check for Updates',
description: 'On launch, EmabssyOS will automatically check for updates of itself and your installed services. Updating still requires user approval and action. No updates will ever be performed automatically.',
default: true,
},
ssh: {
type: 'string',
name: 'SSH Key',
description: 'Add SSH keys to your Embassy to gain root access from the command line.',
nullable: false,
// @TODO regex for SSH Key
// pattern: '',
patternDescription: 'Must be a valid SSH key',
masked: false,
copyable: false,
},
registry: {
type: 'string',
name: 'Marketplace URL',
description: 'The URL of the service marketplace. By default, your Embassy connects to the official Start9 Embassy Marketplace.',
nullable: true,
// @TODO regex for URL
// pattern: '',
patternDescription: 'Must be a valid URL',
changeWarning: 'Downloading services from an alternative marketplace can result in malicious or harmful code being installed on your device.',
default: 'https://registry.start9.com',
masked: false,
copyable: false,
},
// password: {
// type: 'string',
// name: 'Change Password',
// description: 'The master password for your Embassy. Must contain at least 128 bits of entropy.',
// nullable: false,
// // @TODO figure out how to confirm min entropy
// // pattern: '^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[*.!@#$%^&*\]).{12,32}$',
// patternDescription: 'Password too simple. Password must contain at least 128 bits of entroy.',
// changeWarning: 'Changing your password will have no affect on old backups. In order to restore old backups, you must provide the password that was used to create them.',
// masked: true,
// copyable: true,
// },
}