Compare commits

...
9 Commits
29 changed files with 158 additions and 39 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"ansible.python.interpreterPath": "/opt/homebrew/bin/python3" "ansible.python.interpreterPath": "/opt/homebrew/bin/python3"
} }
+1 -1
View File
@@ -125,4 +125,4 @@ enforcement ladder](https://github.com/mozilla/diversity).
For answers to common questions about this code of conduct, see the FAQ at For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations. https://www.contributor-covenant.org/translations.
+1 -1
View File
@@ -120,7 +120,7 @@ func (u *DeviceService) Update(key, value string) error {
if err := ntp.UpdateSystemTimeZone(value); err != nil { if err := ntp.UpdateSystemTimeZone(value); err != nil {
return err return err
} }
go common.RestartService(true, true, false) go common.RestartService(global.IsMaster, true, false)
case "DNS": case "DNS":
if err := updateDNS(strings.Split(value, ",")); err != nil { if err := updateDNS(strings.Split(value, ",")); err != nil {
return err return err
+10 -2
View File
@@ -283,11 +283,19 @@ func (m McpServerService) BindDomain(req request.McpBindDomain) error {
} }
} }
group, _ := groupRepo.Get(groupRepo.WithByWebsiteDefault()) group, _ := groupRepo.Get(groupRepo.WithByWebsiteDefault())
domain, err := ParseDomain(req.Domain)
if err != nil {
return err
}
if domain.Port == 0 {
domain.Port = nginxInstall.HttpPort
}
createWebsiteReq := request.WebsiteCreate{ createWebsiteReq := request.WebsiteCreate{
Domains: []request.WebsiteDomain{ Domains: []request.WebsiteDomain{
{ {
Domain: req.Domain, Domain: domain.Domain,
Port: 80, Port: domain.Port,
}, },
}, },
Alias: strings.ToLower(req.Domain), Alias: strings.ToLower(req.Domain),
+7
View File
@@ -102,6 +102,13 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file
runtime.Params = string(forms) runtime.Params = string(forms)
runtime.Status = constant.StatusBuilding runtime.Status = constant.StatusBuilding
go func() {
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(runtime.AppDetailID))
if err == nil {
RequestDownloadCallBack(appDetail.DownloadCallBackUrl)
}
}()
go buildRuntime(runtime, "", "", false) go buildRuntime(runtime, "", "", false)
return return
} }
+20
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"net"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@@ -1443,3 +1444,22 @@ func hasDefaultServer(params []string) bool {
} }
return false return false
} }
func ParseDomain(domain string) (*model.WebsiteDomain, error) {
host, portStr, err := net.SplitHostPort(domain)
if err != nil {
return &model.WebsiteDomain{
Domain: domain,
Port: 0,
}, nil
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("invalid port in domain %s: %v", domain, err)
}
return &model.WebsiteDomain{
Domain: host,
Port: port,
}, nil
}
+1 -1
View File
@@ -31,7 +31,7 @@ func Down(filePath string) (string, error) {
if err := checkCmd(); err != nil { if err := checkCmd(); err != nil {
return "", err return "", err
} }
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s down --remove-orphans", filePath) stdout, err := cmd.RunDefaultWithStdoutBashCfAndTimeOut(global.CONF.DockerConfig.Command+" -f %s down --remove-orphans", 20*time.Minute, filePath)
return stdout, err return stdout, err
} }
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "This section is for professional edition, please sync lice
ErrXpackOutOfDate: "Current license has expired, please import the license again in Panel Settings - License" ErrXpackOutOfDate: "Current license has expired, please import the license again in Panel Settings - License"
ErrXpackLost: "License has reached the maximum retry count, please go to the [Panel Settings] [License] page and click the sync button manually to ensure the professional features work correctly" ErrXpackLost: "License has reached the maximum retry count, please go to the [Panel Settings] [License] page and click the sync button manually to ensure the professional features work correctly"
ErrDeviceLost: "Required files for license verification are missing, please check and try again!" ErrDeviceLost: "Required files for license verification are missing, please check and try again!"
ErrDeviceErr: "The current environment does not match the license import environment. Please edit the license and re-import!"
ErrXpackTimeout: "Request timeout, network connection might be unstable, please try again later!" ErrXpackTimeout: "Request timeout, network connection might be unstable, please try again later!"
ErrUnbindMaster: "Detected nodes in node management, unable to unbind the current license, please remove nodes first and retry!" ErrUnbindMaster: "Detected nodes in node management, unable to unbind the current license, please remove nodes first and retry!"
ErrFreeNodeLimit: "Community version node limit reached, please go to www.lxware.cn/1panel to purchase and retry!" ErrFreeNodeLimit: "Community version node limit reached, please go to www.lxware.cn/1panel to purchase and retry!"
+1
View File
@@ -59,6 +59,7 @@ ErrXpackExceptional: "この部分はプロフェッショナル版機能です
ErrXpackOutOfDate: "現在のライセンスは期限切れです、再度「パネル設定-ライセンス」画面でライセンスをインポートしてください" ErrXpackOutOfDate: "現在のライセンスは期限切れです、再度「パネル設定-ライセンス」画面でライセンスをインポートしてください"
ErrXpackLost: "ライセンスの最大試行回数に達しました、「パネル設定」「ライセンス」ページに移動し、手動で同期ボタンをクリックして、プロフェッショナル版機能が正常に使用できることを確認してください" ErrXpackLost: "ライセンスの最大試行回数に達しました、「パネル設定」「ライセンス」ページに移動し、手動で同期ボタンをクリックして、プロフェッショナル版機能が正常に使用できることを確認してください"
ErrDeviceLost: "ライセンス検証に必要なファイルが失われました。確認して再試行してください!" ErrDeviceLost: "ライセンス検証に必要なファイルが失われました。確認して再試行してください!"
ErrDeviceErr: "現在の環境とライセンスのインポート環境が一致しません。ライセンスを編集して再度インポートしてください!"
ErrXpackTimeout: "リクエストタイムアウト、ネットワーク接続が不安定な可能性があります。後で再試行してください!" ErrXpackTimeout: "リクエストタイムアウト、ネットワーク接続が不安定な可能性があります。後で再試行してください!"
ErrUnbindMaster: "ノード管理にノードが存在するため、現在のライセンスを解除できません。ノードを削除してから再試行してください!" ErrUnbindMaster: "ノード管理にノードが存在するため、現在のライセンスを解除できません。ノードを削除してから再試行してください!"
ErrFreeNodeLimit: "コミュニティ版のノード数が無料上限に達しました、www.lxware.cn/1panel で購入して再試行してください!" ErrFreeNodeLimit: "コミュニティ版のノード数が無料上限に達しました、www.lxware.cn/1panel で購入して再試行してください!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "이 섹션은 프로페셔널 에디션 기능입니다.
ErrXpackOutOfDate: "현재 라이선스가 만료되었습니다. 다시 [패널 설정]-[라이선스] 인터페이스에서 라이선스를 가져오세요." ErrXpackOutOfDate: "현재 라이선스가 만료되었습니다. 다시 [패널 설정]-[라이선스] 인터페이스에서 라이선스를 가져오세요."
ErrXpackLost: "라이선스가 최대 재시도 횟수에 도달했습니다. [패널 설정][라이선스] 페이지로 이동하여 수동으로 동기화 버튼을 클릭하여 프로페셔널 기능을 정상적으로 사용할 수 있도록 하세요." ErrXpackLost: "라이선스가 최대 재시도 횟수에 도달했습니다. [패널 설정][라이선스] 페이지로 이동하여 수동으로 동기화 버튼을 클릭하여 프로페셔널 기능을 정상적으로 사용할 수 있도록 하세요."
ErrDeviceLost: "라이센스 검증에 필요한 파일이 누락되었습니다. 확인 후 다시 시도해 주세요!" ErrDeviceLost: "라이센스 검증에 필요한 파일이 누락되었습니다. 확인 후 다시 시도해 주세요!"
ErrDeviceErr: "현재 환경이 라이선스 가져오기 환경과 일치하지 않습니다. 라이선스를 편집하고 다시 가져오십시오!"
ErrXpackTimeout: "요청 시간 초과, 네트워크 연결이 불안정할 수 있습니다. 나중에 다시 시도해 주세요!" ErrXpackTimeout: "요청 시간 초과, 네트워크 연결이 불안정할 수 있습니다. 나중에 다시 시도해 주세요!"
ErrUnbindMaster: "노드 관리 내에 노드가 존재함을 감지하였습니다. 현재 라이선스를 해제할 수 없습니다. 먼저 제거 후 다시 시도해 주세요!" ErrUnbindMaster: "노드 관리 내에 노드가 존재함을 감지하였습니다. 현재 라이선스를 해제할 수 없습니다. 먼저 제거 후 다시 시도해 주세요!"
ErrFreeNodeLimit: "커뮤니티 에디션 노드 수가 무료 한도에 도달하였습니다. www.lxware.cn/1panel 에서 구매 후 다시 시도해 주세요!" ErrFreeNodeLimit: "커뮤니티 에디션 노드 수가 무료 한도에 도달하였습니다. www.lxware.cn/1panel 에서 구매 후 다시 시도해 주세요!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "Bahagian ini adalah fungsi profesional, sila selaraskan le
ErrXpackOutOfDate: "Lesen semasa telah tamat tempoh, sila muatkan lesen baru di Tetapan Papan Pemuka." ErrXpackOutOfDate: "Lesen semasa telah tamat tempoh, sila muatkan lesen baru di Tetapan Papan Pemuka."
ErrXpackLost: "Lesen telah mencapai bilangan percubaan maksimum, sila ke [Tetapan Papan Pemuka][Lesen] dan klik butang penyelarasan secara manual." ErrXpackLost: "Lesen telah mencapai bilangan percubaan maksimum, sila ke [Tetapan Papan Pemuka][Lesen] dan klik butang penyelarasan secara manual."
ErrDeviceLost: "Fail yang diperlukan untuk pengesahan lesen hilang, sila semak dan cuba lagi!" ErrDeviceLost: "Fail yang diperlukan untuk pengesahan lesen hilang, sila semak dan cuba lagi!"
ErrDeviceErr: "Persekitaran semasa tidak sepadan dengan persekitaran import lesen. Sila edit lesen dan import semula!"
ErrXpackTimeout: "Permintaan tamat masa, sambungan rangkaian mungkin tidak stabil, sila cuba lagi kemudian!" ErrXpackTimeout: "Permintaan tamat masa, sambungan rangkaian mungkin tidak stabil, sila cuba lagi kemudian!"
ErrUnbindMaster: "Terdapat nod dalam pengurusan nod, sila keluarkan dahulu dan cuba lagi!" ErrUnbindMaster: "Terdapat nod dalam pengurusan nod, sila keluarkan dahulu dan cuba lagi!"
ErrFreeNodeLimit: "Jumlah nod versi komuniti telah mencapai had percuma, sila lawati www.lxware.cn/1panel untuk pembelian!" ErrFreeNodeLimit: "Jumlah nod versi komuniti telah mencapai had percuma, sila lawati www.lxware.cn/1panel untuk pembelian!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "Esta parte é uma funcionalidade profissional, por favor s
ErrXpackOutOfDate: "A licença atual expirou, por favor importe uma nova em Configurações do Painel - Licença." ErrXpackOutOfDate: "A licença atual expirou, por favor importe uma nova em Configurações do Painel - Licença."
ErrXpackLost: "A licença atingiu o número máximo de tentativas, acesse [Configurações do Painel][Licença] e clique no botão de sincronização manual." ErrXpackLost: "A licença atingiu o número máximo de tentativas, acesse [Configurações do Painel][Licença] e clique no botão de sincronização manual."
ErrDeviceLost: "Arquivos necessários para a verificação da licença estão faltando, por favor verifique e tente novamente!" ErrDeviceLost: "Arquivos necessários para a verificação da licença estão faltando, por favor verifique e tente novamente!"
ErrDeviceErr: "O ambiente atual não corresponde ao ambiente de importação da licença. Por favor, edite a licença e reimporte!"
ErrXpackTimeout: "Requisição expirou, a conexão de rede pode estar instável, por favor tente novamente mais tarde!" ErrXpackTimeout: "Requisição expirou, a conexão de rede pode estar instável, por favor tente novamente mais tarde!"
ErrUnbindMaster: "Foram encontrados nós na gestão de nós, remova-os primeiro e tente novamente!" ErrUnbindMaster: "Foram encontrados nós na gestão de nós, remova-os primeiro e tente novamente!"
ErrFreeNodeLimit: "O número de nós da versão comunitária atingiu o limite gratuito, por favor acesse www.lxware.cn/1panel para comprar!" ErrFreeNodeLimit: "O número de nós da versão comunitária atingiu o limite gratuito, por favor acesse www.lxware.cn/1panel para comprar!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "Эта часть доступна только в про
ErrXpackOutOfDate: "Текущая лицензия истекла, повторно импортируйте лицензию в разделе Настройки панели - Лицензия." ErrXpackOutOfDate: "Текущая лицензия истекла, повторно импортируйте лицензию в разделе Настройки панели - Лицензия."
ErrXpackLost: "Лицензия достигла максимального количества попыток, перейдите в [Настройки панели][Лицензия] и нажмите кнопку синхронизации вручную." ErrXpackLost: "Лицензия достигла максимального количества попыток, перейдите в [Настройки панели][Лицензия] и нажмите кнопку синхронизации вручную."
ErrDeviceLost: "Необходимые файлы для проверки лицензии отсутствуют, пожалуйста, проверьте и попробуйте снова!" ErrDeviceLost: "Необходимые файлы для проверки лицензии отсутствуют, пожалуйста, проверьте и попробуйте снова!"
ErrDeviceErr: "Текущая среда не соответствует среде импорта лицензии. Отредактируйте лицензию и повторите импорт!"
ErrXpackTimeout: "Время ожидания запроса истекло, возможно нестабильное сетевое соединение, повторите попытку позже!" ErrXpackTimeout: "Время ожидания запроса истекло, возможно нестабильное сетевое соединение, повторите попытку позже!"
ErrUnbindMaster: "В управлении узлами обнаружены узлы, сначала удалите их и повторите попытку!" ErrUnbindMaster: "В управлении узлами обнаружены узлы, сначала удалите их и повторите попытку!"
ErrFreeNodeLimit: "Количество узлов в версии сообщества достигло бесплатного лимита, посетите www.lxware.cn/1panel для покупки!" ErrFreeNodeLimit: "Количество узлов в версии сообщества достигло бесплатного лимита, посетите www.lxware.cn/1panel для покупки!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "該部分為專業版功能,請先在 面板設定-許
ErrXpackOutOfDate: "目前許可證已過期,請重新在 面板設定-許可證 介面匯入許可證" ErrXpackOutOfDate: "目前許可證已過期,請重新在 面板設定-許可證 介面匯入許可證"
ErrXpackLost: "許可證已達到最大重試次數,請進入【面板設定】【許可證】頁面手動點擊同步按鈕,以確保專業版功能正常使用" ErrXpackLost: "許可證已達到最大重試次數,請進入【面板設定】【許可證】頁面手動點擊同步按鈕,以確保專業版功能正常使用"
ErrDeviceLost: "許可證校驗必要檔案遺失,請檢查後重試!" ErrDeviceLost: "許可證校驗必要檔案遺失,請檢查後重試!"
ErrDeviceErr: "當前環境與許可證導入環境不一致,請編輯許可證重新導入!"
ErrXpackTimeout: "請求超時,網路連接可能不穩定,請稍後再試!" ErrXpackTimeout: "請求超時,網路連接可能不穩定,請稍後再試!"
ErrUnbindMaster: "檢測到節點管理內存在節點,無法解綁目前許可證,請先移除後重試!" ErrUnbindMaster: "檢測到節點管理內存在節點,無法解綁目前許可證,請先移除後重試!"
ErrFreeNodeLimit: "社區版節點數量已達免費上限,請前往 www.lxware.cn/1panel 購買後重試!" ErrFreeNodeLimit: "社區版節點數量已達免費上限,請前往 www.lxware.cn/1panel 購買後重試!"
+1
View File
@@ -58,6 +58,7 @@ ErrXpackExceptional: "该部分为专业版功能,请先在 面板设置-许
ErrXpackOutOfDate: "当前许可证已过期,请重新在 面板设置-许可证 界面导入许可证" ErrXpackOutOfDate: "当前许可证已过期,请重新在 面板设置-许可证 界面导入许可证"
ErrXpackLost: "许可证已达到最大重试次数,请进入【面板设置】【许可证】页面手动点击同步按钮,以确保专业版功能正常使用" ErrXpackLost: "许可证已达到最大重试次数,请进入【面板设置】【许可证】页面手动点击同步按钮,以确保专业版功能正常使用"
ErrDeviceLost: "许可证校验必要文件丢失,请检查后重试!" ErrDeviceLost: "许可证校验必要文件丢失,请检查后重试!"
ErrDeviceErr: "当前环境与许可证导入环境不一致,请编辑许可证重新导入!"
ErrXpackTimeout: "请求超时,网络连接可能不稳定,请稍后再试!" ErrXpackTimeout: "请求超时,网络连接可能不稳定,请稍后再试!"
ErrUnbindMaster: "检测到节点管理内存在专业版节点,无法解绑当前许可证,请先移除或解绑后重试!" ErrUnbindMaster: "检测到节点管理内存在专业版节点,无法解绑当前许可证,请先移除或解绑后重试!"
ErrFreeNodeLimit: "社区版节点数量已达到免费上限,请前往 www.lxware.cn/1panel 购买后重试!" ErrFreeNodeLimit: "社区版节点数量已达到免费上限,请前往 www.lxware.cn/1panel 购买后重试!"
+2 -2
View File
@@ -4,14 +4,14 @@
<p align="center"> <p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a> <a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 180px; height: auto;" /></a>
<a href="https://hellogithub.com/repository/71791baf930149ac9b84e1acf186573f" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=71791baf930149ac9b84e1acf186573f&claim_uid=p8vB3kP5CMrthiL&theme=dark&theme=neutral" alt="Featured|HelloGitHub" style="width: 180px; height: auto;" /></a> <a href="https://hellogithub.com/repository/71791baf930149ac9b84e1acf186573f" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=71791baf930149ac9b84e1acf186573f&claim_uid=p8vB3kP5CMrthiL&theme=dark&theme=neutral" alt="Featured|HelloGitHub" style="width: 180px; height: auto;" /></a>
<a href="https://market.aliyun.com/products/53690006/cmjj00062740.html?userCode=kmemb8jp" target="_blank"><img src="https://img.alicdn.com/imgextra/i2/O1CN01H5JIwY1rZ0OobDjnJ_!!6000000005644-2-tps-1000-216.png" alt="1Panel-dev%2F1Panel | Aliyun" style="width: 180px; height: auto;" /></a>
</p> </p>
<p align="center"> <p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a> <a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="License: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a> <a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a> <a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="GitHub Stars"></a> <a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="GitHub Stars"></a>
<a href="https://gitee.com/fit2cloud-feizhiyun/1Panel"><img src="https://gitee.com/fit2cloud-feizhiyun/1Panel/badge/star.svg?theme=gvp" alt="Gitee Stars"></a><br> <a href="https://gitee.com/fit2cloud-feizhiyun/1Panel"><img src="https://gitee.com/fit2cloud-feizhiyun/1Panel/badge/star.svg?theme=gvp" alt="Gitee Stars"></a>
<a href="https://gitcode.com/feizhiyun/1Panel"><img src="https://gitcode.com/feizhiyun/1Panel/star/badge.svg" alt="GitCode Stars"></a><br>
</p> </p>
<p align="center"> <p align="center">
<a href="/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a> <a href="/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
+1 -1
View File
@@ -38,7 +38,7 @@
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"element-plus": "^2.9.9", "element-plus": "2.9.8",
"fit2cloud-ui-plus": "^1.2.2", "fit2cloud-ui-plus": "^1.2.2",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"js-base64": "^3.7.7", "js-base64": "^3.7.7",
+4
View File
@@ -1263,6 +1263,10 @@ const message = {
disableHelper: disableHelper:
'Disabling the selected FTP account will revoke its access permissions. Do you want to continue?', 'Disabling the selected FTP account will revoke its access permissions. Do you want to continue?',
syncHelper: 'Sync FTP account data between server and database. Do you want to continue?', syncHelper: 'Sync FTP account data between server and database. Do you want to continue?',
dirSystem:
'This directory is system-reserved. Modification may cause system crash, please modify and try again!',
dirHelper: 'Enabling FTP requires directory permission changes - please choose carefully',
dirMsg: 'Enabling FTP will modify permissions for the entire {0} directory. Continue?',
}, },
clam: { clam: {
clam: 'Virus scan', clam: 'Virus scan',
+4
View File
@@ -1207,6 +1207,10 @@ const message = {
enableHelper: '選択したFTPアカウントを有効にすると、アクセス許可が復元されます。続けたいですか?', enableHelper: '選択したFTPアカウントを有効にすると、アクセス許可が復元されます。続けたいですか?',
disableHelper: '選択したFTPアカウントを無効にすると、アクセス許可が取り消されます。続けたいですか?', disableHelper: '選択したFTPアカウントを無効にすると、アクセス許可が取り消されます。続けたいですか?',
syncHelper: 'サーバーとデータベースの間でFTPアカウントデータを同期します。続けたいですか?', syncHelper: 'サーバーとデータベースの間でFTPアカウントデータを同期します。続けたいですか?',
dirSystem:
'このディレクトリはシステム予約領域です。変更するとシステムがクラッシュする可能性があります。修正して再試行してください!',
dirHelper: 'FTPを有効にするにはディレクトリ権限の変更が必要です。慎重に選択してください',
dirMsg: 'FTPを有効にすると{0}ディレクトリ全体の権限が変更されます。続行しますか?',
}, },
clam: { clam: {
clam: 'ウイルススキャン', clam: 'ウイルススキャン',
+4
View File
@@ -1196,6 +1196,10 @@ const message = {
enableHelper: '선택한 FTP 계정을 활성화하면 접근 권한이 복원됩니다. 계속하시겠습니까?', enableHelper: '선택한 FTP 계정을 활성화하면 접근 권한이 복원됩니다. 계속하시겠습니까?',
disableHelper: '선택한 FTP 계정을 비활성화하면 접근 권한이 취소됩니다. 계속하시겠습니까?', disableHelper: '선택한 FTP 계정을 비활성화하면 접근 권한이 취소됩니다. 계속하시겠습니까?',
syncHelper: '서버와 데이터베이스 간의 FTP 계정 데이터를 동기화합니다. 계속하시겠습니까?', syncHelper: '서버와 데이터베이스 간의 FTP 계정 데이터를 동기화합니다. 계속하시겠습니까?',
dirSystem:
'이 디렉터리는 시스템 예약 디렉터리입니다. 수정 시 시스템 충돌이 발생할 수 있으니 수정 후 다시 시도하세요!',
dirHelper: 'FTP 활성화를 위해 디렉터리 권한 변경이 필요합니다. 신중하게 선택하세요',
dirMsg: 'FTP 활성화 시 {0} 디렉터리 전체의 권한이 변경됩니다. 계속하시겠습니까?',
}, },
clam: { clam: {
clam: '바이러스 검사', clam: '바이러스 검사',
+4
View File
@@ -1247,6 +1247,10 @@ const message = {
disableHelper: disableHelper:
'Melumpuhkan akaun FTP yang dipilih akan membatalkan kebenaran aksesnya. Adakah anda mahu meneruskan?', 'Melumpuhkan akaun FTP yang dipilih akan membatalkan kebenaran aksesnya. Adakah anda mahu meneruskan?',
syncHelper: 'Selaraskan data akaun FTP antara pelayan dan pangkalan data. Adakah anda mahu meneruskan?', syncHelper: 'Selaraskan data akaun FTP antara pelayan dan pangkalan data. Adakah anda mahu meneruskan?',
dirSystem:
'Direktori ini dikhaskan untuk sistem. Pengubahsuaian mungkin menyebabkan sistem rosak, sila ubah dan cuba lagi!',
dirHelper: 'Membolehkan FTP memerlukan perubahan kebenaran direktori - sila pilih dengan berhati-hati',
dirMsg: 'Membolehkan FTP akan mengubah kebenaran untuk seluruh direktori {0}. Teruskan?',
}, },
clam: { clam: {
clam: 'Imbasan virus', clam: 'Imbasan virus',
+4
View File
@@ -1233,6 +1233,10 @@ const message = {
enableHelper: 'Ativar a conta FTP selecionada restaurará suas permissões de acesso. Deseja continuar?', enableHelper: 'Ativar a conta FTP selecionada restaurará suas permissões de acesso. Deseja continuar?',
disableHelper: 'Desativar a conta FTP selecionada revogará suas permissões de acesso. Deseja continuar?', disableHelper: 'Desativar a conta FTP selecionada revogará suas permissões de acesso. Deseja continuar?',
syncHelper: 'Sincronizar os dados da conta FTP entre o servidor e o banco de dados. Deseja continuar?', syncHelper: 'Sincronizar os dados da conta FTP entre o servidor e o banco de dados. Deseja continuar?',
dirSystem:
'Este diretório é reservado do sistema. Modificações podem causar falhas no sistema. Por favor, modifique e tente novamente!',
dirHelper: 'Habilitar FTP requer alterações nas permissões do diretório - por favor, escolha com cuidado',
dirMsg: 'Habilitar FTP modificará as permissões de todo o diretório {0}. Continuar?',
}, },
clam: { clam: {
clam: 'Scan de vírus', clam: 'Scan de vírus',
+4
View File
@@ -1237,6 +1237,10 @@ const message = {
enableHelper: 'Включение выбранного FTP аккаунта восстановит его права доступа. Хотите продолжить?', enableHelper: 'Включение выбранного FTP аккаунта восстановит его права доступа. Хотите продолжить?',
disableHelper: 'Отключение выбранного FTP аккаунта отзовет его права доступа. Хотите продолжить?', disableHelper: 'Отключение выбранного FTP аккаунта отзовет его права доступа. Хотите продолжить?',
syncHelper: 'Синхронизировать данные FTP аккаунта между сервером и базой данных. Хотите продолжить?', syncHelper: 'Синхронизировать данные FTP аккаунта между сервером и базой данных. Хотите продолжить?',
dirSystem:
'Это системный каталог. Его изменение может вызвать сбой системы. Пожалуйста, измените и повторите попытку!',
dirHelper: 'Для включения FTP требуется изменение прав доступа к каталогу - выбирайте осторожно',
dirMsg: 'Включение FTP изменит права доступа для всего каталога {0}. Продолжить?',
}, },
clam: { clam: {
clam: 'Антивирусное сканирование', clam: 'Антивирусное сканирование',
+3
View File
@@ -1200,6 +1200,9 @@ const message = {
enableHelper: '啟用選取的 FTP 帳號後,該 FTP 帳號將恢復訪問權限,是否繼續操作?', enableHelper: '啟用選取的 FTP 帳號後,該 FTP 帳號將恢復訪問權限,是否繼續操作?',
disableHelper: '停用選取的 FTP 帳號後,該 FTP 帳號將失去訪問權限,是否繼續操作?', disableHelper: '停用選取的 FTP 帳號後,該 FTP 帳號將失去訪問權限,是否繼續操作?',
syncHelper: '同步伺服器與資料庫中的 FTP 帳戶資料,是否繼續操作?', syncHelper: '同步伺服器與資料庫中的 FTP 帳戶資料,是否繼續操作?',
dirSystem: '該目錄為系統保留目錄,修改可能導致系統崩潰,請修改後重試!',
dirHelper: '開啟 FTP 需要修改目錄權限,請謹慎選擇',
dirMsg: '開啟 FTP 將修改整個 {0} 目錄權限,是否繼續?',
}, },
clam: { clam: {
clam: '病毒掃描', clam: '病毒掃描',
+3
View File
@@ -1199,6 +1199,9 @@ const message = {
enableHelper: '启用选中的 FTP 账号后,该 FTP 账号恢复访问权限,是否继续操作?', enableHelper: '启用选中的 FTP 账号后,该 FTP 账号恢复访问权限,是否继续操作?',
disableHelper: '停用选中的 FTP 账号后,该 FTP 账号将失去访问权限,是否继续操作?', disableHelper: '停用选中的 FTP 账号后,该 FTP 账号将失去访问权限,是否继续操作?',
syncHelper: '同步服务器与数据库中的 FTP 账户数据,是否继续操作?', syncHelper: '同步服务器与数据库中的 FTP 账户数据,是否继续操作?',
dirSystem: '该目录为系统保留目录,修改可能导致系统崩溃,请修改后重试!',
dirHelper: '开启 FTP 需要修改目录权限,请谨慎选择',
dirMsg: '开启 FTP 将修改整个 {0} 目录权限,是否继续?',
}, },
clam: { clam: {
clam: '病毒扫描', clam: '病毒扫描',
+22
View File
@@ -819,3 +819,25 @@ export const preloadImage = (url: string): Promise<string> => {
img.src = url; img.src = url;
}); });
}; };
export const isSensitiveLinuxPath = (path) => {
let sensitivePath = [
'/',
'/bin',
'/sbin',
'/usr/bin',
'/usr/sbin',
'/usr/local/bin',
'/etc',
'/lib',
'/lib64',
'/usr/lib',
'/home',
'/tmp',
'/var',
'/dev',
'/proc',
'/sys',
];
return sensitivePath.indexOf(path) !== -1;
};
+12 -7
View File
@@ -279,6 +279,7 @@ let timer: NodeJS.Timer | null = null;
let isInit = ref<boolean>(true); let isInit = ref<boolean>(true);
let isStatusInit = ref<boolean>(true); let isStatusInit = ref<boolean>(true);
let isActive = ref(true); let isActive = ref(true);
let isCurrentActive = ref(true);
const ioReadBytes = ref<Array<number>>([]); const ioReadBytes = ref<Array<number>>([]);
const ioWriteBytes = ref<Array<number>>([]); const ioWriteBytes = ref<Array<number>>([]);
@@ -406,16 +407,19 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
statusRef.value?.acceptParams(currentInfo.value, baseInfo.value); statusRef.value?.acceptParams(currentInfo.value, baseInfo.value);
appRef.value?.acceptParams(); appRef.value?.acceptParams();
if (isInit) { if (isInit) {
try { timer = setInterval(async () => {
timer = setInterval(async () => { try {
if (!isCurrentActive.value) {
throw new Error('jump out');
}
if (isActive.value && !globalStore.isOnRestart) { if (isActive.value && !globalStore.isOnRestart) {
await onLoadCurrentInfo(); await onLoadCurrentInfo();
} }
}, 3000); } catch {
} finally { clearInterval(Number(timer));
clearInterval(Number(timer)); timer = null;
timer = null; }
} }, 3000);
} }
}; };
@@ -554,6 +558,7 @@ onMounted(() => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
window.removeEventListener('focus', onFocus); window.removeEventListener('focus', onFocus);
window.removeEventListener('blur', onBlur); window.removeEventListener('blur', onBlur);
isCurrentActive.value = false;
clearInterval(Number(timer)); clearInterval(Number(timer));
timer = null; timer = null;
}); });
@@ -100,9 +100,14 @@ const onSave = async (formEl: FormInstance | undefined) => {
.then(async () => { .then(async () => {
loading.value = false; loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
globalStore.isLogin = false; if (globalStore.currentNode === 'local') {
let href = window.location.href; globalStore.isLogin = false;
window.open(href, '_self'); let href = window.location.href;
window.open(href, '_self');
} else {
globalStore.currentNode = 'local';
location.reload();
}
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;
@@ -23,6 +23,7 @@
<FileList @choose="loadDir" :dir="true"></FileList> <FileList @choose="loadDir" :dir="true"></FileList>
</template> </template>
</el-input> </el-input>
<span class="input-help">{{ $t('toolbox.ftp.dirHelper') }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" :rows="3" clearable v-model="dialogData.rowData!.description" /> <el-input type="textarea" :rows="3" clearable v-model="dialogData.rowData!.description" />
@@ -48,7 +49,7 @@ import { ElForm } from 'element-plus';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { Toolbox } from '@/api/interface/toolbox'; import { Toolbox } from '@/api/interface/toolbox';
import { createFtp, updateFtp } from '@/api/modules/toolbox'; import { createFtp, updateFtp } from '@/api/modules/toolbox';
import { getRandomStr } from '@/utils/util'; import { getRandomStr, isSensitiveLinuxPath } from '@/utils/util';
interface DialogProps { interface DialogProps {
title: string; title: string;
@@ -77,10 +78,18 @@ const handleClose = () => {
drawerVisible.value = false; drawerVisible.value = false;
}; };
const verifyPath = (rule: any, value: any, callback: any) => {
if (isSensitiveLinuxPath(dialogData.value.rowData.path)) {
callback(new Error(i18n.global.t('toolbox.ftp.dirSystem')));
return;
}
callback();
};
const rules = reactive({ const rules = reactive({
user: [Rules.simpleName], user: [Rules.simpleName],
password: [Rules.simplePassword], password: [Rules.simplePassword],
path: [Rules.requiredInput, Rules.noSpace], path: [Rules.requiredInput, Rules.noSpace, { validator: verifyPath, trigger: 'change', required: true }],
}); });
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
@@ -94,32 +103,37 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return; if (!formEl) return;
formEl.validate(async (valid) => { formEl.validate(async (valid) => {
if (!valid) return; if (!valid) return;
loading.value = true; ElMessageBox.confirm(i18n.global.t('toolbox.ftp.dirMsg', [dialogData.value.rowData.path]), 'FTP', {
if (dialogData.value.title === 'edit') { confirmButtonText: i18n.global.t('commons.button.confirm'),
await updateFtp(dialogData.value.rowData) cancelButtonText: i18n.global.t('commons.button.cancel'),
}).then(async () => {
loading.value = true;
if (dialogData.value.title === 'edit') {
await updateFtp(dialogData.value.rowData)
.then(() => {
loading.value = false;
drawerVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
})
.catch(() => {
loading.value = false;
});
return;
}
await createFtp(dialogData.value.rowData)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
drawerVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search'); emit('search');
drawerVisible.value = false;
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;
}); });
});
return;
}
await createFtp(dialogData.value.rowData)
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisible.value = false;
})
.catch(() => {
loading.value = false;
});
}); });
}; };