mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/start tunnel (#3037)
* fix live-build resolv.conf * improved debuggability * wip: start-tunnel * fixes for trixie and tor * non-free-firmware on trixie * wip * web server WIP * wip: tls refactor * FE patchdb, mocks, and most endpoints * fix editing records and patch mocks * refactor complete * finish api * build and formatter update * minor change toi viewing addresses and fix build * fixes * more providers * endpoint for getting config * fix tests * api fixes * wip: separate port forward controller into parts * simplify iptables rules * bump sdk * misc fixes * predict next subnet and ip, use wan ips, and form validation * refactor: break big components apart and address todos (#3043) * refactor: break big components apart and address todos * starttunnel readme, fix pf mocks, fix adding tor domain in startos --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * better tui * tui tweaks * fix: address comments * better regex for subnet * fixes * better validation * handle rpc errors * build fixes * fix: address comments (#3044) * fix: address comments * fix unread notification mocks * fix row click for notification --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix raspi build * fix build * fix build * fix build * fix build * try to fix build * fix tests * fix tests * fix rsync tests * delete useless effectful test --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> Co-authored-by: Alex Inkin <alexander@inkin.ru>
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
import { inject, Injectable } from '@angular/core'
|
||||
import { shareReplay, Subject, tap } from 'rxjs'
|
||||
import { WebSocketSubject } from 'rxjs/webSocket'
|
||||
import {
|
||||
AddForwardReq,
|
||||
ApiService,
|
||||
DeleteDeviceReq,
|
||||
DeleteForwardReq,
|
||||
DeleteSubnetReq,
|
||||
LoginReq,
|
||||
SubscribeRes,
|
||||
UpsertDeviceReq,
|
||||
UpsertSubnetReq,
|
||||
} from './api.service'
|
||||
import { pauseFor } from '@start9labs/shared'
|
||||
import { AuthService } from '../auth.service'
|
||||
import {
|
||||
AddOperation,
|
||||
Operation,
|
||||
PatchOp,
|
||||
RemoveOperation,
|
||||
ReplaceOperation,
|
||||
Revision,
|
||||
} from 'patch-db-client'
|
||||
import { toObservable } from '@angular/core/rxjs-interop'
|
||||
import { mockTunnelData, WgClient, WgSubnet } from '../patch-db/data-model'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MockApiService extends ApiService {
|
||||
private readonly auth = inject(AuthService)
|
||||
readonly mockWsSource$ = new Subject<Revision>()
|
||||
sequence = 1
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
toObservable(this.auth.authenticated)
|
||||
.pipe(
|
||||
tap(() => {
|
||||
this.sequence = 1
|
||||
}),
|
||||
)
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
openWebsocket$<T>(guid: string): WebSocketSubject<T> {
|
||||
return this.mockWsSource$.pipe(
|
||||
shareReplay({ bufferSize: 1, refCount: true }),
|
||||
) as WebSocketSubject<T>
|
||||
}
|
||||
|
||||
async subscribe(): Promise<SubscribeRes> {
|
||||
await pauseFor(1000)
|
||||
return {
|
||||
dump: { id: 1, value: mockTunnelData },
|
||||
guid: 'patch-db-guid',
|
||||
}
|
||||
}
|
||||
|
||||
async login(params: LoginReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
return null
|
||||
}
|
||||
|
||||
async logout(): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
return null
|
||||
}
|
||||
|
||||
async setPassword(params: LoginReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
return null
|
||||
}
|
||||
|
||||
async addSubnet(params: UpsertSubnetReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: AddOperation<WgSubnet>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}`,
|
||||
value: { name: params.name, clients: {} },
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async editSubnet(params: UpsertSubnetReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: ReplaceOperation<string>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}/name`,
|
||||
value: params.name,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteSubnet(params: DeleteSubnetReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async addDevice(params: UpsertDeviceReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: AddOperation<WgClient>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}/clients/${params.ip}`,
|
||||
value: { name: params.name },
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async editDevice(params: UpsertDeviceReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: ReplaceOperation<string>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}/clients/${params.ip}/name`,
|
||||
value: params.name,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteDevice(params: DeleteDeviceReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/wg/subnets/${replaceSlashes(params.subnet)}/clients/${params.ip}`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async showDeviceConfig(params: DeleteDeviceReq): Promise<string> {
|
||||
await pauseFor(1000)
|
||||
|
||||
return MOCK_CONFIG
|
||||
}
|
||||
|
||||
async addForward(params: AddForwardReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: AddOperation<string>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/portForwards/${params.source}`,
|
||||
value: params.target,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteForward(params: DeleteForwardReq): Promise<null> {
|
||||
await pauseFor(1000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/portForwards/${params.source}`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private async mockRevision<T>(patch: Operation<T>[]): Promise<void> {
|
||||
const revision = {
|
||||
id: ++this.sequence,
|
||||
patch,
|
||||
}
|
||||
this.mockWsSource$.next(revision)
|
||||
}
|
||||
}
|
||||
|
||||
function replaceSlashes(val: string) {
|
||||
return val.replace(new RegExp('/', 'g'), '~1')
|
||||
}
|
||||
|
||||
const MOCK_CONFIG = `[Interface]
|
||||
# Server's private IP address for the WireGuard VPN subnet
|
||||
Address = 10.20.10.1/24
|
||||
# UDP port WireGuard listens on
|
||||
ListenPort = 33333
|
||||
# Server private key (generated)
|
||||
PrivateKey = 4K68mdpQWdEz/FpdVuRoZYgWpQgpW63J9GFzn+iOulQ=
|
||||
|
||||
# Commands to run after starting/stopping WireGuard tunnel to enable forwarding and NAT (example)
|
||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
|
||||
|
||||
# Add client peers below with their public keys and allowed IPs
|
||||
[Peer]
|
||||
# Client public key
|
||||
PublicKey = MQBiYHxAj7u8paj3L4w4uav3P/9YBPbaN4gkWn90SSs=
|
||||
# Allowed client IP address within VPN subnet`
|
||||
Reference in New Issue
Block a user