123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- import { forwardRef, useImperativeHandle, useState } from "react";
- import { useLockFn } from "ahooks";
- import { useTranslation } from "react-i18next";
- import {
- InputAdornment,
- List,
- ListItem,
- ListItemText,
- styled,
- TextField,
- Typography,
- Button,
- } from "@mui/material";
- import { useVerge } from "@/hooks/use-verge";
- import { getSystemProxy, getAutotemProxy } from "@/services/cmds";
- import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
- import { Edit } from "@mui/icons-material";
- import { EditorViewer } from "@/components/profile/editor-viewer";
- import { BaseFieldset } from "@/components/base/base-fieldset";
- import getSystem from "@/utils/get-system";
- import { TooltipIcon } from "@/components/base/base-tooltip-icon";
- const DEFAULT_PAC = `function FindProxyForURL(url, host) {
- return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
- }`;
- export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
- const { t } = useTranslation();
- let validReg;
- if (getSystem() === "windows") {
- validReg =
- /^((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>)(;((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>))*;?$/;
- } else {
- validReg =
- /^((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>)(,((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>))*,?$/;
- }
- const [open, setOpen] = useState(false);
- const [editorOpen, setEditorOpen] = useState(false);
- const { verge, patchVerge } = useVerge();
- type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
- const [sysproxy, setSysproxy] = useState<SysProxy>();
- type AutoProxy = Awaited<ReturnType<typeof getAutotemProxy>>;
- const [autoproxy, setAutoproxy] = useState<AutoProxy>();
- const {
- enable_system_proxy: enabled,
- proxy_auto_config,
- pac_file_content,
- enable_proxy_guard,
- system_proxy_bypass,
- proxy_guard_duration,
- } = verge ?? {};
- const [value, setValue] = useState({
- guard: enable_proxy_guard,
- bypass: system_proxy_bypass,
- duration: proxy_guard_duration ?? 10,
- pac: proxy_auto_config,
- pac_content: pac_file_content ?? DEFAULT_PAC,
- });
- useImperativeHandle(ref, () => ({
- open: () => {
- setOpen(true);
- setValue({
- guard: enable_proxy_guard,
- bypass: system_proxy_bypass,
- duration: proxy_guard_duration ?? 10,
- pac: proxy_auto_config,
- pac_content: pac_file_content ?? DEFAULT_PAC,
- });
- getSystemProxy().then((p) => setSysproxy(p));
- getAutotemProxy().then((p) => setAutoproxy(p));
- },
- close: () => setOpen(false),
- }));
- const onSave = useLockFn(async () => {
- if (value.duration < 1) {
- Notice.error(t("Proxy Daemon Duration Cannot be Less than 1 Second"));
- return;
- }
- const patch: Partial<IVergeConfig> = {};
- if (value.guard !== enable_proxy_guard) {
- patch.enable_proxy_guard = value.guard;
- }
- if (value.duration !== proxy_guard_duration) {
- patch.proxy_guard_duration = value.duration;
- }
- if (value.bypass !== system_proxy_bypass) {
- patch.system_proxy_bypass = value.bypass;
- }
- if (value.pac !== proxy_auto_config) {
- patch.proxy_auto_config = value.pac;
- }
- if (value.pac_content !== pac_file_content) {
- patch.pac_file_content = value.pac_content;
- }
- if (value.bypass && !validReg.test(value.bypass)) {
- Notice.error(t("Invalid Bypass Format"));
- return;
- }
- try {
- await patchVerge(patch);
- setOpen(false);
- } catch (err: any) {
- Notice.error(err.message || err.toString());
- }
- });
- return (
- <BaseDialog
- open={open}
- title={t("System Proxy Setting")}
- contentSx={{ width: 450, maxHeight: 565 }}
- okBtn={t("Save")}
- cancelBtn={t("Cancel")}
- onClose={() => setOpen(false)}
- onCancel={() => setOpen(false)}
- onOk={onSave}
- >
- <List>
- <BaseFieldset label={t("Current System Proxy")} padding="15px 10px">
- <FlexBox>
- <Typography className="label">{t("Enable status")}</Typography>
- <Typography className="value">
- {value.pac
- ? autoproxy?.enable
- ? t("Enabled")
- : t("Disabled")
- : sysproxy?.enable
- ? t("Enabled")
- : t("Disabled")}
- </Typography>
- </FlexBox>
- {!value.pac && (
- <>
- <FlexBox>
- <Typography className="label">{t("Server Addr")}</Typography>
- <Typography className="value">
- {sysproxy?.server ? sysproxy.server : t("Not available")}
- </Typography>
- </FlexBox>
- </>
- )}
- {value.pac && (
- <FlexBox>
- <Typography className="label">{t("PAC URL")}</Typography>
- <Typography className="value">{autoproxy?.url || "-"}</Typography>
- </FlexBox>
- )}
- </BaseFieldset>
- <ListItem sx={{ padding: "5px 2px" }}>
- <ListItemText primary={t("Use PAC Mode")} />
- <Switch
- edge="end"
- disabled={!enabled}
- checked={value.pac}
- onChange={(_, e) => setValue((v) => ({ ...v, pac: e }))}
- />
- </ListItem>
- <ListItem sx={{ padding: "5px 2px" }}>
- <ListItemText
- primary={t("Proxy Guard")}
- sx={{ maxWidth: "fit-content" }}
- />
- <TooltipIcon title={t("Proxy Guard Info")} />
- <Switch
- edge="end"
- disabled={!enabled}
- checked={value.guard}
- onChange={(_, e) => setValue((v) => ({ ...v, guard: e }))}
- sx={{ marginLeft: "auto" }}
- />
- </ListItem>
- <ListItem sx={{ padding: "5px 2px" }}>
- <ListItemText primary={t("Guard Duration")} />
- <TextField
- disabled={!enabled}
- size="small"
- value={value.duration}
- sx={{ width: 100 }}
- InputProps={{
- endAdornment: <InputAdornment position="end">s</InputAdornment>,
- }}
- onChange={(e) => {
- setValue((v) => ({
- ...v,
- duration: +e.target.value.replace(/\D/, ""),
- }));
- }}
- />
- </ListItem>
- {!value.pac && (
- <>
- <ListItemText primary={t("Proxy Bypass")} />
- <TextField
- error={value.bypass ? !validReg.test(value.bypass) : false}
- disabled={!enabled}
- size="small"
- autoComplete="off"
- multiline
- rows={4}
- sx={{ width: "100%" }}
- value={value.bypass}
- onChange={(e) => {
- setValue((v) => ({ ...v, bypass: e.target.value }));
- }}
- />
- <ListItemText primary={t("Bypass")} />
- <FlexBox>
- <TextField
- disabled={true}
- size="small"
- autoComplete="off"
- multiline
- rows={4}
- sx={{ width: "100%" }}
- value={sysproxy?.bypass || "-"}
- />
- </FlexBox>
- </>
- )}
- {value.pac && (
- <>
- <ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
- <ListItemText
- primary={t("PAC Script Content")}
- sx={{ padding: "3px 0" }}
- />
- <Button
- startIcon={<Edit />}
- variant="outlined"
- onClick={() => {
- setEditorOpen(true);
- }}
- >
- {t("Edit")} PAC
- </Button>
- <EditorViewer
- title={`${t("Edit")} PAC`}
- mode="text"
- property={value.pac_content ?? ""}
- open={editorOpen}
- language="javascript"
- onChange={(content) => {
- let pac = DEFAULT_PAC;
- if (content && content.trim().length > 0) {
- pac = content;
- }
- setValue((v) => ({ ...v, pac_content: pac }));
- }}
- onClose={() => {
- setEditorOpen(false);
- }}
- />
- </ListItem>
- </>
- )}
- </List>
- </BaseDialog>
- );
- });
- const FlexBox = styled("div")`
- display: flex;
- margin-top: 4px;
- .label {
- flex: none;
- //width: 85px;
- }
- `;
|