mirror of
https://github.com/warp-tech/warpgate.git
synced 2024-09-20 06:46:17 +08:00
lint
This commit is contained in:
parent
d90aa7d2b0
commit
892e0173ac
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4128,6 +4128,7 @@ dependencies = [
|
|||
name = "warpgate-db-migrations"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"chrono",
|
||||
"sea-orm",
|
||||
"sea-orm-migration",
|
||||
|
|
5
justfile
5
justfile
|
@ -18,6 +18,9 @@ yarn *ARGS:
|
|||
migrate *ARGS:
|
||||
cargo run -p warpgate-db-migrations -- {{ARGS}}
|
||||
|
||||
lint:
|
||||
cd warpgate-admin/app/ && yarn run lint
|
||||
|
||||
svelte-check:
|
||||
cd warpgate-admin/app/ && yarn run check
|
||||
|
||||
|
@ -27,4 +30,4 @@ openapi-all:
|
|||
openapi:
|
||||
cd warpgate-admin/app/ && yarn openapi-client
|
||||
|
||||
cleanup: (fix "--allow-dirty") (clippy "--fix" "--allow-dirty") fmt svelte-check
|
||||
cleanup: (fix "--allow-dirty") (clippy "--fix" "--allow-dirty") fmt svelte-check lint
|
||||
|
|
|
@ -53,6 +53,7 @@ rules:
|
|||
'@typescript-eslint/no-use-before-define':
|
||||
- error
|
||||
- classes: false
|
||||
functions: false
|
||||
no-duplicate-imports: error
|
||||
array-bracket-spacing:
|
||||
- error
|
||||
|
@ -130,12 +131,22 @@ rules:
|
|||
- allowAliases: in-unions-and-intersections
|
||||
allowLiterals: always
|
||||
allowCallbacks: always
|
||||
'@typescript-eslint/comma-dangle':
|
||||
- error
|
||||
- arrays: always-multiline
|
||||
objects: always-multiline
|
||||
imports: always-multiline
|
||||
exports: always-multiline
|
||||
functions: only-multiline
|
||||
|
||||
overrides:
|
||||
- files: '*.svelte'
|
||||
processor: svelte3/svelte3
|
||||
rules:
|
||||
# To allow prop definitions
|
||||
'@typescript-eslint/init-declarations': off
|
||||
# False positives for {#if}
|
||||
'@typescript-eslint/no-unnecessary-condition': off
|
||||
|
||||
ignorePatterns:
|
||||
- svelte.config.js
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"lint": "eslint src && svelte-check",
|
||||
"postinstall": "yarn run openapi-client",
|
||||
"openapi-schema": "curl -k https://localhost:8888/api/openapi.json > openapi-schema.json",
|
||||
"openapi-client": "openapi-generator-cli generate -g typescript-fetch -i openapi-schema.json -o api-client -p npmName=warpgate-api-client -p useSingleRequestParameter=true && cd api-client && npm i && npm run build",
|
||||
"openapi-client": "openapi-generator-cli generate -g typescript-fetch -i openapi-schema.json -o api-client -p npmName=warpgate-api-client -p useSingleRequestParameter=true && cd api-client && npm i && yarn tsc --target esnext --module esnext && rm -rf src",
|
||||
"openapi": "yarn run openapi-schema && yarn run openapi-client"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { faSignOut } from '@fortawesome/free-solid-svg-icons'
|
||||
import { api } from 'lib/api'
|
||||
import { authenticatedUsername } from 'lib/store'
|
||||
import Fa from 'svelte-fa'
|
||||
import { Fa } from 'svelte-fa'
|
||||
|
||||
import logo from '../public/assets/logo.svg'
|
||||
|
||||
|
@ -31,31 +31,31 @@ init()
|
|||
|
||||
const routes = {
|
||||
'/': wrap({
|
||||
asyncComponent: () => import('./Home.svelte')
|
||||
asyncComponent: () => import('./Home.svelte'),
|
||||
}),
|
||||
'/login': wrap({
|
||||
asyncComponent: () => import('./Login.svelte')
|
||||
asyncComponent: () => import('./Login.svelte'),
|
||||
}),
|
||||
'/sessions/:id': wrap({
|
||||
asyncComponent: () => import('./Session.svelte')
|
||||
asyncComponent: () => import('./Session.svelte'),
|
||||
}),
|
||||
'/recordings/:id': wrap({
|
||||
asyncComponent: () => import('./Recording.svelte')
|
||||
asyncComponent: () => import('./Recording.svelte'),
|
||||
}),
|
||||
'/tickets': wrap({
|
||||
asyncComponent: () => import('./Tickets.svelte')
|
||||
asyncComponent: () => import('./Tickets.svelte'),
|
||||
}),
|
||||
'/tickets/create': wrap({
|
||||
asyncComponent: () => import('./CreateTicket.svelte')
|
||||
asyncComponent: () => import('./CreateTicket.svelte'),
|
||||
}),
|
||||
'/targets': wrap({
|
||||
asyncComponent: () => import('./Targets.svelte')
|
||||
asyncComponent: () => import('./Targets.svelte'),
|
||||
}),
|
||||
'/ssh': wrap({
|
||||
asyncComponent: () => import('./SSH.svelte')
|
||||
asyncComponent: () => import('./SSH.svelte'),
|
||||
}),
|
||||
'/log': wrap({
|
||||
asyncComponent: () => import('./Log.svelte')
|
||||
asyncComponent: () => import('./Log.svelte'),
|
||||
}),
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -33,7 +33,7 @@ async function create () {
|
|||
createTicketRequest: {
|
||||
username: selectedUser.username,
|
||||
targetName: selectedTarget.name,
|
||||
}
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
error = err
|
||||
|
@ -59,11 +59,11 @@ async function create () {
|
|||
<h3>Connection instructions</h3>
|
||||
|
||||
<FormGroup floating label="SSH username">
|
||||
<input type="text" class="form-control" readonly value={"ticket-" + result.secret} />
|
||||
<input type="text" class="form-control" readonly value={'ticket-' + result.secret} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup floating label="Example command">
|
||||
<input type="text" class="form-control" readonly value={"ssh ticket-" + result.secret + "@warpgate-host -p warpgate-port"} />
|
||||
<input type="text" class="form-control" readonly value={'ssh ticket-' + result.secret + '@warpgate-host -p warpgate-port'} />
|
||||
</FormGroup>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import Fa from 'svelte-fa'
|
||||
import { Fa } from 'svelte-fa'
|
||||
import { faCircleDot as iconActive } from '@fortawesome/free-regular-svg-icons'
|
||||
import { Spinner, Button } from 'sveltestrap'
|
||||
import { onDestroy } from 'svelte'
|
||||
|
@ -7,7 +7,7 @@
|
|||
import { api, SessionSnapshot } from 'lib/api'
|
||||
import { derived, writable } from 'svelte/store'
|
||||
import { firstBy } from 'thenby'
|
||||
import moment from 'moment'
|
||||
import moment, { duration } from 'moment'
|
||||
import RelativeDate from 'RelativeDate.svelte'
|
||||
|
||||
const sessions = writable<SessionSnapshot[]|null>(null)
|
||||
|
@ -73,7 +73,7 @@
|
|||
|
||||
<div class="meta">
|
||||
{#if session.ended }
|
||||
{moment.duration(moment(session.ended).diff(session.started)).humanize()}
|
||||
{duration(moment(session.ended).diff(session.started)).humanize()}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { api, LogEntry } from 'lib/api'
|
||||
import { Alert, FormGroup } from 'sveltestrap'
|
||||
import { firstBy } from 'thenby';
|
||||
import { Alert } from 'sveltestrap'
|
||||
import { firstBy } from 'thenby'
|
||||
import IntersectionObserver from 'svelte-intersection-observer'
|
||||
import { link } from 'svelte-spa-router'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
@ -59,18 +59,18 @@ async function loadNewer () {
|
|||
}
|
||||
}
|
||||
|
||||
async function loadOlder (search = false) {
|
||||
async function loadOlder (searchMode = false) {
|
||||
loading = true
|
||||
try {
|
||||
const newItems = await api.getLogs({
|
||||
getLogsRequest: {
|
||||
...filters ?? {},
|
||||
before: search ? undefined : items?.at(-1)?.timestamp,
|
||||
before: searchMode ? undefined : items?.at(-1)?.timestamp,
|
||||
limit: PAGE_SIZE,
|
||||
search: searchQuery,
|
||||
},
|
||||
})
|
||||
if (search) {
|
||||
if (searchMode) {
|
||||
endReached = false
|
||||
items = []
|
||||
}
|
||||
|
@ -109,7 +109,6 @@ onDestroy(() => {
|
|||
clearInterval(reloadInterval)
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
|
|
|
@ -9,13 +9,7 @@ let username = ''
|
|||
let password = ''
|
||||
let incorrectCredentials = false
|
||||
|
||||
function onInputKey (event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
login()
|
||||
}
|
||||
}
|
||||
|
||||
async function login (event?) {
|
||||
async function login (event?: MouseEvent) {
|
||||
event?.preventDefault()
|
||||
error = null
|
||||
incorrectCredentials = false
|
||||
|
@ -26,11 +20,11 @@ async function login (event?) {
|
|||
password,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
if (error.status === 401) {
|
||||
} catch (err) {
|
||||
if (err.status === 401) {
|
||||
incorrectCredentials = true
|
||||
} else {
|
||||
error = error
|
||||
error = err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -38,6 +32,12 @@ async function login (event?) {
|
|||
authenticatedUsername.set(info.username!)
|
||||
replace('/')
|
||||
}
|
||||
|
||||
function onInputKey (event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
login()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="mt-5 row" autocomplete="on">
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { api, Recording, RecordingKind } from 'lib/api'
|
||||
import { api, Recording } from 'lib/api'
|
||||
import { Alert, Spinner } from 'sveltestrap'
|
||||
import TerminalRecordingPlayer from 'player/TerminalRecordingPlayer.svelte'
|
||||
import { onDestroy } from 'svelte';
|
||||
|
||||
export let params = { id: '' }
|
||||
|
||||
|
@ -11,7 +10,6 @@ let recording: Recording|null = null
|
|||
|
||||
async function load () {
|
||||
recording = await api.getRecording(params)
|
||||
|
||||
}
|
||||
|
||||
function getTCPDumpURL () {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { api, SessionSnapshot, Recording } from 'lib/api'
|
||||
import { timeAgo } from 'lib/time'
|
||||
import moment from 'moment'
|
||||
import { onDestroy } from 'svelte';
|
||||
import moment, { duration } from 'moment'
|
||||
import { onDestroy } from 'svelte'
|
||||
import { link } from 'svelte-spa-router'
|
||||
import { Alert, Button, FormGroup, Spinner } from 'sveltestrap'
|
||||
import { Alert, Button, Spinner } from 'sveltestrap'
|
||||
import LogViewer from 'LogViewer.svelte'
|
||||
import RelativeDate from 'RelativeDate.svelte'
|
||||
|
||||
|
@ -64,10 +64,10 @@ onDestroy(() => clearInterval(interval))
|
|||
{getTargetDescription()}
|
||||
</strong>
|
||||
<span class="text-muted">
|
||||
{moment.duration(moment(session.ended).diff(session.started)).humanize()} long, <RelativeDate date={session.started} />
|
||||
{duration(moment(session.ended).diff(session.started)).humanize()} long, <RelativeDate date={session.started} />
|
||||
</span>
|
||||
{:else}
|
||||
{moment.duration(moment().diff(session.started)).humanize()}
|
||||
{duration(moment().diff(session.started)).humanize()}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { api, Target, UserSnapshot } from 'lib/api'
|
||||
import { getSSHUsername } from 'lib/ssh';
|
||||
import { getSSHUsername } from 'lib/ssh'
|
||||
import { Alert, FormGroup, Modal, ModalBody, ModalHeader } from 'sveltestrap'
|
||||
|
||||
let error: Error|undefined
|
||||
|
@ -86,7 +86,7 @@ $: sshUsername = getSSHUsername(selectedUser, selectedTarget)
|
|||
</FormGroup>
|
||||
|
||||
<FormGroup floating label="Example command">
|
||||
<input type="text" class="form-control" readonly value={"ssh " + sshUsername + "@warpgate-host -p warpgate-port"} />
|
||||
<input type="text" class="form-control" readonly value={'ssh ' + sshUsername + '@warpgate-host -p warpgate-port'} />
|
||||
</FormGroup>
|
||||
{/if}
|
||||
</ModalBody>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { api, Ticket } from 'lib/api'
|
||||
import { link } from 'svelte-spa-router'
|
||||
import { Alert } from 'sveltestrap'
|
||||
import RelativeDate from 'RelativeDate.svelte';
|
||||
import RelativeDate from 'RelativeDate.svelte'
|
||||
|
||||
let error: Error|undefined
|
||||
let tickets: Ticket[]|undefined
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
|
@ -1,8 +1,8 @@
|
|||
import { DefaultApi, Configuration } from '../../api-client/src'
|
||||
import { DefaultApi, Configuration } from '../../api-client/dist'
|
||||
|
||||
const configuration = new Configuration({
|
||||
basePath: '/api'
|
||||
basePath: '/api',
|
||||
})
|
||||
|
||||
export const api = new DefaultApi(configuration)
|
||||
export * from '../../api-client/src/models'
|
||||
export * from '../../api-client'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { Target, UserSnapshot } from './api'
|
||||
|
||||
export function getSSHUsername (user: UserSnapshot|undefined, target: Target|undefined): string {
|
||||
return `${user?.username ?? "<username>"}:${target?.name}`
|
||||
return `${user?.username ?? '<username>'}:${target?.name}`
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import moment from 'moment'
|
||||
|
||||
export function timeAgo(t: any): string {
|
||||
export function timeAgo (t: Date): string {
|
||||
return moment(t).fromNow()
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import './theme.scss'
|
|||
import App from './App.svelte'
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById('app')!
|
||||
target: document.getElementById('app')!,
|
||||
})
|
||||
|
||||
export default app
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import Fa from 'svelte-fa'
|
||||
import { Fa } from 'svelte-fa'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import { Terminal } from 'xterm'
|
||||
import { SerializeAddon } from 'xterm-addon-serialize'
|
||||
|
@ -16,7 +16,7 @@
|
|||
let timestamp = 0
|
||||
let seekInputValue = 0
|
||||
let duration = 0
|
||||
let resizeObserver: ResizeObserver
|
||||
let resizeObserver: ResizeObserver|undefined
|
||||
let events: (SizeEvent | DataEvent | SnapshotEvent)[] = []
|
||||
let playing = false
|
||||
let loading = true
|
||||
|
@ -64,14 +64,15 @@
|
|||
width: number
|
||||
height: number
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-type-alias
|
||||
type AsciiCastData = [number, 'o', string]
|
||||
type AsciiCastItem = AsciiCastHeader | AsciiCastData
|
||||
|
||||
function isAsciiCastHeader(data: AsciiCastItem): data is AsciiCastHeader {
|
||||
function isAsciiCastHeader (data: AsciiCastItem): data is AsciiCastHeader {
|
||||
return 'version' in data
|
||||
}
|
||||
|
||||
function isAsciiCastData(data: AsciiCastItem): data is AsciiCastData {
|
||||
function isAsciiCastData (data: AsciiCastItem): data is AsciiCastData {
|
||||
return data[1] === 'o'
|
||||
}
|
||||
|
||||
|
@ -163,7 +164,7 @@
|
|||
function fitSize () {
|
||||
metricsCanvas ??= document.createElement('canvas')
|
||||
const context = metricsCanvas.getContext('2d')!
|
||||
context.font = '10px ' + term.options.fontFamily ?? 'monospace'
|
||||
context.font = `10px ${term.options.fontFamily ?? 'monospace'}`
|
||||
const metrics = context.measureText('abcdef')
|
||||
|
||||
const fontWidth = containerElement.clientWidth / term.cols
|
||||
|
@ -172,12 +173,12 @@
|
|||
|
||||
let seekPromise = Promise.resolve()
|
||||
|
||||
async function seek (time) {
|
||||
async function seek (time: number) {
|
||||
seekPromise = seekPromise.then(() => _seekInternal(time))
|
||||
await seekPromise
|
||||
}
|
||||
|
||||
async function _seekInternal (time) {
|
||||
async function _seekInternal (time: number) {
|
||||
let nearestSnapshot: SnapshotEvent|null = null
|
||||
|
||||
for (const event of events) {
|
||||
|
@ -253,7 +254,7 @@
|
|||
seekInputValue = 100 * time / duration
|
||||
}
|
||||
|
||||
function resize (cols, rows) {
|
||||
function resize (cols: number, rows: number) {
|
||||
if (term.cols === cols && term.rows === rows) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -12,5 +12,12 @@ export default defineConfig({
|
|||
],
|
||||
build: {
|
||||
sourcemap: true,
|
||||
commonjsOptions: {
|
||||
include: [
|
||||
'api-client/dist/*.js',
|
||||
'**/*.js',
|
||||
],
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -181,10 +181,7 @@ pub async fn api_get_recording_stream(
|
|||
if let Some(mut receiver) = receiver {
|
||||
tokio::spawn(async move {
|
||||
if let Err(error) = async {
|
||||
loop {
|
||||
let Ok(data) = receiver.recv().await else {
|
||||
break;
|
||||
};
|
||||
while let Ok(data) = receiver.recv().await {
|
||||
let content: TerminalRecordingItem = serde_json::from_slice(&data)?;
|
||||
let cast: AsciiCast = content.into();
|
||||
let msg = serde_json::to_string(&json!({ "data": cast }))?;
|
||||
|
|
|
@ -48,7 +48,9 @@ pub fn install_database_logger(database: Arc<Mutex<DatabaseConnection>>) {
|
|||
fn values_to_log_entry_data(mut values: SerializedRecordValues) -> Option<LogEntry::ActiveModel> {
|
||||
let session_id = (*values).remove("session");
|
||||
let username = (*values).remove("session_username");
|
||||
let message = (*values).remove("message").unwrap_or("".to_string());
|
||||
let message = (*values)
|
||||
.remove("message")
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
|
||||
use sea_orm::ActiveValue::Set;
|
||||
let session_id = session_id.and_then(|x| Uuid::parse_str(&x).ok());
|
||||
|
|
|
@ -7,7 +7,7 @@ version = "0.1.0"
|
|||
[dependencies]
|
||||
chrono = {version = "0.4", features = ["serde"]}
|
||||
poem-openapi = {version = "^1.3.30", features = ["chrono", "uuid"]}
|
||||
sea-orm = {version = "^0.8", features = ["macros", "with-chrono", "with-uuid"], default-features = false}
|
||||
sea-orm = {version = "^0.8", features = ["macros", "with-chrono", "with-uuid", "with-json"], default-features = false}
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
uuid = {version = "0.8", features = ["v4", "serde"]}
|
||||
|
|
|
@ -27,16 +27,6 @@ pub struct Model {
|
|||
pub kind: RecordingKind,
|
||||
}
|
||||
|
||||
// #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
// pub enum Relation {
|
||||
// #[sea_orm(
|
||||
// belongs_to = "super::Session::Entity",
|
||||
// from = "Column::SessionId",
|
||||
// to = "super::Session::Column::Id"
|
||||
// )]
|
||||
// Session,
|
||||
// }
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Session,
|
||||
|
|
|
@ -8,6 +8,7 @@ version = "0.1.0"
|
|||
[lib]
|
||||
|
||||
[dependencies]
|
||||
async-std = "^1.11"
|
||||
chrono = "0.4"
|
||||
sea-orm = {version = "^0.8", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"], default-features = false}
|
||||
sea-orm-migration = {version = "^0.8", default-features = false}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use sea_orm::DatabaseConnection;
|
||||
use sea_orm_migration::MigrationTrait;
|
||||
use sea_orm_migration::prelude::*;
|
||||
use sea_orm_migration::MigrationTrait;
|
||||
|
||||
mod m00001_create_ticket;
|
||||
mod m00002_create_session;
|
||||
|
@ -24,5 +24,5 @@ impl MigratorTrait for Migrator {
|
|||
}
|
||||
|
||||
pub async fn migrate_database(connection: &DatabaseConnection) -> Result<(), DbErr> {
|
||||
Migrator::up(&connection, None).await
|
||||
Migrator::up(connection, None).await
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use sea_schema::migration::*;
|
||||
use sea_orm_migration::prelude::*;
|
||||
use warpgate_db_migrations::Migrator;
|
||||
|
||||
#[async_std::main]
|
||||
|
|
Loading…
Reference in a new issue