mirror of
https://github.com/wireadmin/wireadmin
synced 2025-03-09 13:20:39 +00:00
Adds a feature for removing duplicate lines in the torrc
file, and provides a few minor updates to the UI.
This commit is contained in:
parent
379d715ecd
commit
b55cb8a025
@ -35,16 +35,16 @@ EOF
|
||||
cat /etc/tor/bridges >>/etc/tor/torrc
|
||||
fi
|
||||
|
||||
# Removing duplicated lines form /etc/tor/torrc file
|
||||
awk '!seen[$0]++' /etc/tor/torrc >/tmp/torrc
|
||||
mv /tmp/torrc /etc/tor/torrc
|
||||
|
||||
# any other environment variables that start with TOR_ are added to the torrc
|
||||
# file
|
||||
env | grep ^TOR_ | sed -e 's/TOR_//' -e 's/=/ /' >>/etc/tor/torrc
|
||||
|
||||
# Removing duplicated lines form /etc/tor/torrc file
|
||||
awk '!seen[$0]++' /etc/tor/torrc >/tmp/torrc
|
||||
mv /tmp/torrc /etc/tor/torrc
|
||||
|
||||
# Start Tor in the background
|
||||
screen -L -Logfile /var/vlogs/tor -dmS tor bash -c "tor"
|
||||
screen -L -Logfile /var/vlogs/tor -dmS tor bash -c "tor -f /etc/tor/torrc"
|
||||
|
||||
# Starting Redis server in detached mode
|
||||
screen -L -Logfile /var/vlogs/redis -dmS redis bash -c "redis-server --port 6479 --daemonize no --dir /data --appendonly yes"
|
||||
|
@ -17,6 +17,7 @@ import { getPeerConf } from "@lib/wireguard-utils";
|
||||
import EditableText from "@ui/EditableText";
|
||||
import { RLS_NAME_INPUT } from "@lib/form-rules";
|
||||
import { UPDATE_CLIENT } from "@lib/swr-fetch";
|
||||
import CopiableWrapper from "@ui/CopiableWrapper";
|
||||
|
||||
|
||||
export async function getServerSideProps(context: any) {
|
||||
@ -42,15 +43,13 @@ export default function ServerPage(props: PageProps) {
|
||||
async (url: string) => {
|
||||
const resp = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
if (resp.status === 404) {
|
||||
router.replace('/').catch()
|
||||
return false
|
||||
}
|
||||
const data = await resp.json() as APIResponse<any>
|
||||
const data = await resp.json() as APIResponse<WgServer>
|
||||
if (!data.ok) throw new Error('Server responded with error status')
|
||||
return data.result
|
||||
}
|
||||
@ -58,17 +57,11 @@ export default function ServerPage(props: PageProps) {
|
||||
|
||||
const { isMutating: isChangingStatus, trigger: changeStatus } = useSWRMutation(
|
||||
`/api/wireguard/${props.serverId}`,
|
||||
async (url: string, { arg }: {
|
||||
arg: string
|
||||
}) => {
|
||||
async (url: string, { arg }: { arg: string }) => {
|
||||
const resp = await fetch(url, {
|
||||
method: arg === 'remove' ? 'DELETE' : 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: arg === 'remove' ? undefined : JSON.stringify({
|
||||
status: arg
|
||||
})
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: arg === 'remove' ? undefined : JSON.stringify({ status: arg })
|
||||
})
|
||||
if (resp.status === 404) {
|
||||
router.replace('/').catch()
|
||||
@ -98,7 +91,7 @@ export default function ServerPage(props: PageProps) {
|
||||
{ title: data ? data.name.toString() : 'LOADING...' }
|
||||
]}
|
||||
/>
|
||||
{error ? (
|
||||
{error || (!isLoading && !data) ? (
|
||||
<Card className={'flex items-center justify-center p-4'}>
|
||||
! ERROR !
|
||||
</Card>
|
||||
@ -106,21 +99,26 @@ export default function ServerPage(props: PageProps) {
|
||||
<Card className={'flex items-center justify-center p-4'}>
|
||||
Loading...
|
||||
</Card>
|
||||
) : (
|
||||
) : data && (
|
||||
<div className={'space-y-4'}>
|
||||
<Card className={'[&>.ant-card-body]:max-md:p1-2'}>
|
||||
<List>
|
||||
<Row label={'IP address'}>
|
||||
<pre> {data.address}/24 </pre>
|
||||
</Row>
|
||||
<Row label={'Listen Port'}>
|
||||
<pre> {data.listen} </pre>
|
||||
</Row>
|
||||
<Row label={'Status'}>
|
||||
<StatusBadge status={data.status} />
|
||||
</Row>
|
||||
<Row label={'Public Key'}>
|
||||
<CopiableWrapper content={data.publicKey}>
|
||||
<MiddleEllipsis
|
||||
content={data.publicKey}
|
||||
maxLength={16}
|
||||
/>
|
||||
</CopiableWrapper>
|
||||
</Row>
|
||||
</List>
|
||||
<div className={'flex flex-wrap items-center gap-2 mt-6'}>
|
||||
@ -269,12 +267,13 @@ function Client(props: ClientProps) {
|
||||
<List.Item key={props.id} className={'flex items-center justify-between p-4'}>
|
||||
<QRCodeModal ref={qrcodeRef} content={conf?.trim() || 'null'} />
|
||||
<div className={'w-full flex flex-row items-center gap-x-2'}>
|
||||
<div className={'w-12 aspect-square flex items-center justify-center mr-4 rounded-full bg-gray-200'}>
|
||||
{/* User Icon */}
|
||||
|
||||
<div
|
||||
className={'w-12 aspect-square flex items-center justify-center mr-4 rounded-full bg-gray-200 max-md:hidden'}>
|
||||
<i className={'fas fa-user text-gray-400 text-lg'} />
|
||||
</div>
|
||||
<div className={'col-span-12 md:col-span-4'}>
|
||||
<div className={'col-span-12 md:col-span-4'}>
|
||||
|
||||
<div className={'flex flex-col items-start justify-between'}>
|
||||
<EditableText
|
||||
disabled={isMutating}
|
||||
rules={RLS_NAME_INPUT}
|
||||
@ -283,11 +282,11 @@ function Client(props: ClientProps) {
|
||||
content={props.name}
|
||||
onChange={(v) => trigger({ name: v })}
|
||||
/>
|
||||
</div>
|
||||
<div className={'col-span-12 md:col-span-4'}>
|
||||
<CopiableWrapper content={props.allowedIps} className={'text-sm'} showInHover={true}>
|
||||
<span className={'font-mono text-gray-400 text-xs'}> {props.allowedIps} </span>
|
||||
</CopiableWrapper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={'flex items-center justify-center gap-x-3'}>
|
||||
{/* QRCode */}
|
||||
|
@ -15,6 +15,7 @@ import EditableText from "@ui/EditableText";
|
||||
import useSWRMutation from "swr/mutation";
|
||||
import { UPDATE_SERVER } from "@lib/swr-fetch";
|
||||
import { RLS_NAME_INPUT } from "@lib/form-rules";
|
||||
import CopiableWrapper from "@ui/CopiableWrapper";
|
||||
|
||||
export default function Home() {
|
||||
const { data, error, isLoading, mutate } = useSWR(
|
||||
@ -99,16 +100,26 @@ function ServerListItem(props: ServerListItemProps) {
|
||||
|
||||
return (
|
||||
<List.Item className={'flex items-center justify-between p-4'}>
|
||||
<div className={'w-full grid grid-cols-12 items-center gap-x-2'}>
|
||||
<ServerIcon type={props.type} className={'col-span-1'} />
|
||||
<div className={'w-full grid grid-cols-8 md:grid-cols-12 items-center gap-x-1'}>
|
||||
<ServerIcon type={props.type} className={'max-md:hidden md:col-span-1'} />
|
||||
<div className={'flex flex-col justify-between col-span-4'}>
|
||||
<EditableText
|
||||
disabled={isMutating}
|
||||
rules={RLS_NAME_INPUT}
|
||||
rootClassName={'font-medium col-span-4'}
|
||||
inputClassName={'w-20'}
|
||||
rootClassName={'font-medium'}
|
||||
inputClassName={'w-full max-w-[120px]'}
|
||||
content={props.name}
|
||||
onChange={(v) => trigger({ name: v })}
|
||||
/>
|
||||
<CopiableWrapper
|
||||
content={`${props.address}:${props.listen}`}
|
||||
className={'text-sm'}
|
||||
rootClassName={'mt-0.5'}
|
||||
showInHover={true}
|
||||
>
|
||||
<span className={'font-mono text-gray-400 text-xs'}> {props.address}:{props.listen} </span>
|
||||
</CopiableWrapper>
|
||||
</div>
|
||||
<div className={'col-span-4 justify-end'}>
|
||||
<StatusBadge status={props.status} />
|
||||
</div>
|
||||
@ -129,13 +140,13 @@ type ServerIconProps = {
|
||||
|
||||
function ServerIcon(props: ServerIconProps) {
|
||||
return (
|
||||
<div className={props.className}>
|
||||
<div className={'w-fit relative'}>
|
||||
<div className={twMerge('flex items-start', props.className)}>
|
||||
<div className={'w-fit h-full relative'}>
|
||||
<Image
|
||||
src={'/vps.29373866.svg'}
|
||||
alt={'VPS'}
|
||||
width={34}
|
||||
height={34}
|
||||
width={40}
|
||||
height={40}
|
||||
/>
|
||||
{props.type !== 'direct' && (
|
||||
<div className={'absolute -bottom-1 -right-2 rounded-full bg-white'}>
|
||||
|
40
src/ui/CopiableWrapper.tsx
Normal file
40
src/ui/CopiableWrapper.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import { ReactHTMLProps } from "@lib/typings";
|
||||
import { message } from "antd";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export interface CopiableWrapperProps extends Omit<ReactHTMLProps<HTMLSpanElement>, 'content'> {
|
||||
rootClassName?: string
|
||||
content: string | number
|
||||
showInHover?: boolean
|
||||
}
|
||||
|
||||
export default function CopiableWrapper(props: CopiableWrapperProps) {
|
||||
const {
|
||||
content,
|
||||
children,
|
||||
rootClassName,
|
||||
className,
|
||||
showInHover = false,
|
||||
...rest
|
||||
} = props
|
||||
const [ messageApi, contextHolder ] = message.useMessage()
|
||||
return (
|
||||
<div className={twMerge('group flex items-center', rootClassName)}>
|
||||
{contextHolder}
|
||||
{children}
|
||||
<i {...rest}
|
||||
className={twMerge(
|
||||
'ml-2 mb-0.5 far fa-copy cursor-pointer text-gray-400/80 hover:text-primary',
|
||||
showInHover && 'group-hover:opacity-100 opacity-0',
|
||||
className
|
||||
)}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(content.toString())
|
||||
.then(() => messageApi.success('Copied!'))
|
||||
.catch()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -39,7 +39,7 @@ export default function EditableText(props: EditableTextProps) {
|
||||
}, [ val ])
|
||||
const [ form ] = Form.useForm()
|
||||
return (
|
||||
<div className={twMerge('group', rootClassName)}>
|
||||
<div className={twMerge('group block', rootClassName)}>
|
||||
<span {...rest} className={twMerge(
|
||||
editMode ? 'hidden' : 'flex items-center gap-x-2',
|
||||
'leading-none'
|
||||
|
Loading…
Reference in New Issue
Block a user