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:
Shahrad Elahi 2023-09-28 10:19:20 +03:30
parent 379d715ecd
commit b55cb8a025
5 changed files with 104 additions and 54 deletions

View File

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

View File

@ -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'}>
<MiddleEllipsis
content={data.publicKey}
maxLength={16}
/>
<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,25 +267,26 @@ 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'}>
<EditableText
disabled={isMutating}
rules={RLS_NAME_INPUT}
rootClassName={'font-medium col-span-4'}
inputClassName={'w-20'}
content={props.name}
onChange={(v) => trigger({ name: v })}
/>
</div>
<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}
rootClassName={'font-medium col-span-4'}
inputClassName={'w-20'}
content={props.name}
onChange={(v) => trigger({ name: v })}
/>
<CopiableWrapper content={props.allowedIps} className={'text-sm'} showInHover={true}>
<span className={'font-mono text-gray-400 text-xs'}> {props.allowedIps} </span>
</div>
</CopiableWrapper>
</div>
</div>
<div className={'flex items-center justify-center gap-x-3'}>
{/* QRCode */}

View File

@ -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'} />
<EditableText
disabled={isMutating}
rules={RLS_NAME_INPUT}
rootClassName={'font-medium col-span-4'}
inputClassName={'w-20'}
content={props.name}
onChange={(v) => trigger({ name: v })}
/>
<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'}
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'}>

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

View File

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