Skip to content

Commit 7336cb0

Browse files
committed
feat: inspect DNS and profile
1 parent d127eed commit 7336cb0

File tree

14 files changed

+403
-38
lines changed

14 files changed

+403
-38
lines changed

src/App.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ const ScriptingPage = loadable(() => import('./pages/Scripting'), {
4646
const EvaluatePage = loadable(() => import('./pages/Scripting/Evaluate'), {
4747
fallback: <FullLoading />,
4848
})
49+
const DnsPage = loadable(() => import('./pages/Dns'), {
50+
fallback: <FullLoading />,
51+
})
52+
const ProfilePage = loadable(() => import('./pages/Profiles/Current'), {
53+
fallback: <FullLoading />,
54+
})
4955
const ToastContainer = styled(OriginalToastContainer)`
5056
${tw`p-2 md:p-0`}
5157
@@ -188,6 +194,12 @@ const App: React.FC = () => {
188194
<Route exact path="/scripting/evaluate">
189195
<EvaluatePage />
190196
</Route>
197+
<Route exact path="/dns">
198+
<DnsPage />
199+
</Route>
200+
<Route exact path="/profiles/current">
201+
<ProfilePage />
202+
</Route>
191203
<Route path="*">
192204
<Redirect to="/" />
193205
</Route>
File renamed without changes.

src/pages/Dns/index.tsx

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/** @jsx jsx */
2+
import { jsx } from '@emotion/core'
3+
import { Button } from '@sumup/circuit-ui'
4+
import SelectorGroup from '@sumup/circuit-ui/dist/es/components/SelectorGroup'
5+
import React, {
6+
ChangeEvent,
7+
MouseEventHandler,
8+
useCallback,
9+
useMemo,
10+
useState,
11+
} from 'react'
12+
import css from '@emotion/css/macro'
13+
import { toast } from 'react-toastify'
14+
import tw from 'twin.macro'
15+
import useSWR, { mutate } from 'swr'
16+
import { List, AutoSizer, ListRowRenderer } from 'react-virtualized'
17+
18+
import PageTitle from '../../components/PageTitle'
19+
import { DnsResult } from '../../types'
20+
import fetcher from '../../utils/fetcher'
21+
22+
const Page: React.FC = () => {
23+
const [group, setGroup] = useState<'dynamic' | 'static'>('dynamic')
24+
const { data: dnsResult, error: dnsResultError } = useSWR<DnsResult>(
25+
'/dns',
26+
fetcher,
27+
)
28+
const list = useMemo(() => {
29+
if (group === 'dynamic') {
30+
return dnsResult?.dnsCache ?? []
31+
}
32+
return dnsResult?.local ?? []
33+
}, [dnsResult, group])
34+
35+
const flushDns: MouseEventHandler = () => {
36+
fetcher({
37+
url: '/dns/flush',
38+
method: 'POST',
39+
})
40+
.then(() => {
41+
toast.success('操作成功')
42+
return mutate('/dns')
43+
})
44+
.catch((err) => {
45+
console.error(err)
46+
})
47+
}
48+
49+
const openIpDetail = (ip: string) => {
50+
window.open(`https://ip.sb/ip/${ip}`, '_blank', 'noopener noreferrer')
51+
}
52+
53+
const rowRenderer: ListRowRenderer = useCallback(
54+
({
55+
key, // Unique key within array of rows
56+
index, // Index of row within collection
57+
isScrolling, // The List is currently being scrolled
58+
isVisible, // This row is visible within the List (eg it is not an overscanned row)
59+
style, // Style object to be applied to row (to position it)
60+
}) => {
61+
if (group === 'dynamic') {
62+
const record = (list as DnsResult['dnsCache'])[index]
63+
64+
return (
65+
<div
66+
key={key}
67+
style={style}
68+
onClick={() => openIpDetail(record.data[0])}
69+
css={[
70+
tw`flex flex-col justify-center py-2 cursor-pointer hover:bg-gray-100`,
71+
css`
72+
padding-left: calc(env(safe-area-inset-left) + 0.75rem);
73+
padding-right: calc(env(safe-area-inset-right) + 0.75rem);
74+
`,
75+
]}>
76+
<div tw="text-sm truncate">{record.domain}</div>
77+
<div tw="text-xs text-gray-700 leading-tight">
78+
DNS: {record.server}
79+
</div>
80+
<div tw="text-xs text-gray-700 leading-tight truncate">
81+
Result: {record.data.join(', ')}
82+
</div>
83+
<div tw="text-xs text-gray-700 leading-tight truncate">
84+
Path: {record.path}
85+
</div>
86+
</div>
87+
)
88+
} else {
89+
const record = (list as DnsResult['local'])[index]
90+
91+
return (
92+
<div
93+
key={key}
94+
style={style}
95+
css={[
96+
tw`flex flex-col justify-center py-2`,
97+
css`
98+
padding-left: calc(env(safe-area-inset-left) + 0.75rem);
99+
padding-right: calc(env(safe-area-inset-right) + 0.75rem);
100+
`,
101+
]}>
102+
<div tw="text-sm truncate">{record.domain}</div>
103+
{!!record.server && (
104+
<div tw="text-xs text-gray-700 leading-tight">
105+
DNS: {record.server}
106+
</div>
107+
)}
108+
<div tw="text-xs text-gray-700 leading-tight">
109+
Result: {record.data ?? 'N/A'}
110+
</div>
111+
<div tw="text-xs text-gray-700 leading-tight">
112+
Source: {record.source ?? 'N/A'}
113+
</div>
114+
{!!record.comment && (
115+
<div tw="text-xs text-gray-700 leading-tight">
116+
{record.comment}
117+
</div>
118+
)}
119+
</div>
120+
)
121+
}
122+
},
123+
[group, list],
124+
)
125+
126+
return (
127+
<div tw="fixed top-0 right-0 bottom-0 left-0 h-full">
128+
<div tw="w-full h-full flex flex-col">
129+
<PageTitle title="DNS" />
130+
131+
<div tw="flex-1">
132+
<AutoSizer>
133+
{({ width, height }) => {
134+
return (
135+
<List
136+
width={width}
137+
height={height}
138+
rowCount={list.length}
139+
rowHeight={85}
140+
rowRenderer={rowRenderer}
141+
style={{
142+
outline: 'none',
143+
}}
144+
css={css`
145+
& > div {
146+
${tw`divide-y divide-gray-200`}
147+
}
148+
`}
149+
/>
150+
)
151+
}}
152+
</AutoSizer>
153+
</div>
154+
155+
<div
156+
css={css`
157+
padding-bottom: env(safe-area-inset-bottom);
158+
`}>
159+
<div
160+
css={[
161+
tw`flex divide-x divide-gray-200 border-t border-solid border-gray-200 py-2 px-2`,
162+
css`
163+
& > div {
164+
${tw`mx-2`}
165+
}
166+
& > div:first-of-type {
167+
margin-left: 0;
168+
}
169+
`,
170+
]}>
171+
<SelectorGroup
172+
css={[
173+
tw`flex justify-center items-center`,
174+
css`
175+
& label {
176+
${tw`py-2 px-4 ml-2 my-1 text-sm`}
177+
}
178+
& label:first-of-type {
179+
margin-left: 0;
180+
}
181+
`,
182+
]}
183+
label="choose the dns result group"
184+
name="selector-group"
185+
onChange={(event: ChangeEvent<HTMLInputElement>) => {
186+
setGroup(event.target.value as 'dynamic' | 'static')
187+
}}
188+
options={[
189+
{
190+
children: 'Dynamic',
191+
value: 'dynamic',
192+
},
193+
{
194+
children: 'Static',
195+
value: 'static',
196+
},
197+
]}
198+
value={group}
199+
/>
200+
201+
<div tw="flex items-center">
202+
<Button
203+
tw="font-normal"
204+
variant="tertiary"
205+
size="kilo"
206+
onClick={flushDns}>
207+
Flush DNS
208+
</Button>
209+
</div>
210+
</div>
211+
</div>
212+
</div>
213+
</div>
214+
)
215+
}
216+
217+
export default Page

src/pages/Index/components/Events.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const Events: React.FC = () => {
2121
<div tw="text-base font-medium text-gray-700">Events</div>
2222
<div tw="divide-y divide-gray-200 mt-1">
2323
{events &&
24-
events.events.slice(0, 5).map((item) => {
24+
events.events.slice(0, 8).map((item) => {
2525
return (
2626
<div key={item.identifier} tw="py-1">
2727
<div

src/pages/Index/components/TrafficCell/index.tsx

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -118,24 +118,35 @@ const Index: React.FC = () => {
118118
<div tw="mb-3 w-full overflow-hidden">
119119
<LineChart id="traffic-chart" newDatasets={newDatasets} />
120120
</div>
121-
<div tw="grid grid-cols-3 gap-4 divide-x divide-gray-200 border-solid border border-gray-200 bg-gray-100">
122-
{activeInterface && (
123-
<React.Fragment>
124-
<Cell>
125-
<Title>Upload</Title>
126-
<Data>{bytes(activeInterface.outCurrentSpeed)}/s</Data>
127-
</Cell>
128-
<Cell>
129-
<Title>Download</Title>
130-
<Data>{bytes(activeInterface.inCurrentSpeed)}/s</Data>
131-
</Cell>
132-
<Cell>
133-
<Title>Total</Title>
134-
<Data>{bytes(activeInterface.in + activeInterface.out)}</Data>
135-
</Cell>
136-
</React.Fragment>
137-
)}
138-
</div>
121+
122+
{activeInterface ? (
123+
<div tw="grid grid-cols-3 gap-4 divide-x divide-gray-200 border-solid border border-gray-200 bg-gray-100">
124+
<Cell>
125+
<Title>Upload</Title>
126+
<Data>{bytes(activeInterface.outCurrentSpeed)}/s</Data>
127+
</Cell>
128+
<Cell>
129+
<Title>Download</Title>
130+
<Data>{bytes(activeInterface.inCurrentSpeed)}/s</Data>
131+
</Cell>
132+
<Cell>
133+
<Title>Total</Title>
134+
<Data>{bytes(activeInterface.in + activeInterface.out)}</Data>
135+
</Cell>
136+
</div>
137+
) : (
138+
<div
139+
css={[
140+
tw`border border-gray-200 bg-gray-100 text-gray-700`,
141+
css`
142+
height: 67px;
143+
line-height: 67px;
144+
text-align: center;
145+
`,
146+
]}>
147+
Loading...
148+
</div>
149+
)}
139150
</div>
140151
)
141152
}

src/pages/Index/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import useSWR, { mutate } from 'swr'
1111

1212
import { DataGroup, DataRow, DataRowMain } from '../../components/Data'
1313
import ProfileCell from '../../components/ProfileCell'
14+
import Ad from '../../components/Ad'
1415
import { useProfile } from '../../models/profile'
1516
import { Capability } from '../../types'
1617
import fetcher from '../../utils/fetcher'
17-
import Ad from './components/Ad'
1818
import TrafficCell from './components/TrafficCell'
1919
import Events from './components/Events'
2020
import MenuTile, { MenuTileTitle } from './components/MenuTile'
@@ -69,7 +69,7 @@ const Page: React.FC = () => {
6969
if (!link) return
7070

7171
if (link.startsWith('http')) {
72-
window.open(link)
72+
window.open(link, '_blank', 'noopener noreferrer')
7373
} else {
7474
history.push(link)
7575
}

src/pages/Index/menu.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ const menu: Array<MenuItem> = [
4141
title: 'Modules',
4242
link: '/modules',
4343
},
44+
{
45+
title: 'DNS',
46+
link: '/dns',
47+
},
48+
{
49+
title: 'Profile',
50+
link: '/profiles/current',
51+
},
4452
{
4553
title: 'MitM',
4654
component: <CapabilityTile api="/features/mitm" title="MitM" />,

src/pages/Landing/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { find } from 'lodash-es'
1616
import { useHistory } from 'react-router-dom'
1717

1818
import ProfileCell from '../../components/ProfileCell'
19+
import Ad from '../../components/Ad'
1920
import useSetState from '../../hooks/use-set-state'
2021
import { Profile } from '../../types'
2122
import { ExistingProfiles, LastUsedProfile } from '../../utils/constant'
@@ -321,6 +322,10 @@ const Page: React.FC = () => {
321322
</div>
322323
</div>
323324
)}
325+
326+
<div tw="max-w-xs sm:max-w-sm md:max-w-md mx-auto mt-10">
327+
<Ad />
328+
</div>
324329
</div>
325330
)
326331
}

src/pages/Modules/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { RadioButton } from '@sumup/circuit-ui'
55
import styled from '@emotion/styled/macro'
66
import tw from 'twin.macro'
77
import useSWR, { mutate } from 'swr'
8-
import PageTitle from '../../components/PageTitle'
98

9+
import PageTitle from '../../components/PageTitle'
1010
import { Modules } from '../../types'
1111
import fetcher from '../../utils/fetcher'
1212

0 commit comments

Comments
 (0)