mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-10 08:00:32 +00:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67ce559b12 | ||
|
|
71869b7264 | ||
|
|
03774bbba6 | ||
|
|
e07b6bc050 | ||
|
|
b1935d8368 | ||
|
|
f8e344db76 | ||
|
|
2c3a8dd6af | ||
|
|
86e5fc36f4 | ||
|
|
858cefc0c9 | ||
|
|
4535c0b90b | ||
|
|
136489e346 | ||
|
|
e2882fd1cc | ||
|
|
dba97076df | ||
|
|
000bcd37c1 | ||
|
|
bf28223745 | ||
|
|
1fed5c4d15 |
@@ -44,6 +44,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
|||||||
- [在线文档](https://1panel.cn/docs/)
|
- [在线文档](https://1panel.cn/docs/)
|
||||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||||
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
||||||
|
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
|
||||||
|
|
||||||
## 安全说明
|
## 安全说明
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -173,7 +175,7 @@ type diskInfo struct {
|
|||||||
|
|
||||||
func loadDiskInfo() []dto.DiskInfo {
|
func loadDiskInfo() []dto.DiskInfo {
|
||||||
var datas []dto.DiskInfo
|
var datas []dto.DiskInfo
|
||||||
stdout, err := cmd.Exec("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")
|
stdout, err := cmd.ExecWithTimeOut("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev", 2*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return datas
|
return datas
|
||||||
}
|
}
|
||||||
@@ -207,24 +209,52 @@ func loadDiskInfo() []dto.DiskInfo {
|
|||||||
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
|
mounts = append(mounts, diskInfo{Type: fields[1], Device: fields[0], Mount: fields[6]})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
wg sync.WaitGroup
|
||||||
|
mu sync.Mutex
|
||||||
|
)
|
||||||
|
wg.Add(len(mounts))
|
||||||
for i := 0; i < len(mounts); i++ {
|
for i := 0; i < len(mounts); i++ {
|
||||||
state, err := disk.Usage(mounts[i].Mount)
|
go func(timeoutCh <-chan time.Time, mount diskInfo) {
|
||||||
if err != nil {
|
defer wg.Done()
|
||||||
continue
|
|
||||||
}
|
var itemData dto.DiskInfo
|
||||||
var itemData dto.DiskInfo
|
itemData.Path = mount.Mount
|
||||||
itemData.Path = mounts[i].Mount
|
itemData.Type = mount.Type
|
||||||
itemData.Type = mounts[i].Type
|
itemData.Device = mount.Device
|
||||||
itemData.Device = mounts[i].Device
|
select {
|
||||||
itemData.Total = state.Total
|
case <-timeoutCh:
|
||||||
itemData.Free = state.Free
|
mu.Lock()
|
||||||
itemData.Used = state.Used
|
datas = append(datas, itemData)
|
||||||
itemData.UsedPercent = state.UsedPercent
|
mu.Unlock()
|
||||||
itemData.InodesTotal = state.InodesTotal
|
global.LOG.Errorf("load disk info from %s failed, err: timeout", mount.Mount)
|
||||||
itemData.InodesUsed = state.InodesUsed
|
default:
|
||||||
itemData.InodesFree = state.InodesFree
|
state, err := disk.Usage(mount.Mount)
|
||||||
itemData.InodesUsedPercent = state.InodesUsedPercent
|
if err != nil {
|
||||||
datas = append(datas, itemData)
|
mu.Lock()
|
||||||
|
datas = append(datas, itemData)
|
||||||
|
mu.Unlock()
|
||||||
|
global.LOG.Errorf("load disk info from %s failed, err: %v", mount.Mount, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itemData.Total = state.Total
|
||||||
|
itemData.Free = state.Free
|
||||||
|
itemData.Used = state.Used
|
||||||
|
itemData.UsedPercent = state.UsedPercent
|
||||||
|
itemData.InodesTotal = state.InodesTotal
|
||||||
|
itemData.InodesUsed = state.InodesUsed
|
||||||
|
itemData.InodesFree = state.InodesFree
|
||||||
|
itemData.InodesUsedPercent = state.InodesUsedPercent
|
||||||
|
mu.Lock()
|
||||||
|
datas = append(datas, itemData)
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
}(time.After(5*time.Second), mounts[i])
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
sort.Slice(datas, func(i, j int) bool {
|
||||||
|
return datas[i].Path < datas[j].Path
|
||||||
|
})
|
||||||
return datas
|
return datas
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,12 +217,12 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
case "create":
|
case "create":
|
||||||
registries = common.RemoveRepeatElement(append(registries, newHost))
|
registries = common.RemoveRepeatElement(append(registries, newHost))
|
||||||
case "update":
|
case "update":
|
||||||
registries = common.RemoveRepeatElement(append(registries, newHost))
|
|
||||||
for i, regi := range registries {
|
for i, regi := range registries {
|
||||||
if regi == delHost {
|
if regi == delHost {
|
||||||
registries = append(registries[:i], registries[i+1:]...)
|
registries = append(registries[:i], registries[i+1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
registries = common.RemoveRepeatElement(append(registries, newHost))
|
||||||
case "delete":
|
case "delete":
|
||||||
for i, regi := range registries {
|
for i, regi := range registries {
|
||||||
if regi == delHost {
|
if regi == delHost {
|
||||||
|
|||||||
@@ -196,8 +196,11 @@ func opNginx(containerName, operate string) error {
|
|||||||
if operate == constant.NginxCheck {
|
if operate == constant.NginxCheck {
|
||||||
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
||||||
}
|
}
|
||||||
if out, err := cmd.ExecWithTimeOut(nginxCmd, 2*time.Second); err != nil {
|
if out, err := cmd.ExecWithTimeOut(nginxCmd, 20*time.Second); err != nil {
|
||||||
return errors.New(out)
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2093,15 +2093,8 @@ func (w WebsiteService) OperateRedirect(req request.NginxRedirectReq) (err error
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
case "404":
|
case "404":
|
||||||
if req.KeepPath && !req.RedirectRoot {
|
|
||||||
target = req.Target + "$request_uri"
|
|
||||||
}
|
|
||||||
if req.RedirectRoot {
|
if req.RedirectRoot {
|
||||||
target = "/"
|
target = "/"
|
||||||
} else {
|
|
||||||
if req.KeepPath {
|
|
||||||
target = req.Target + "$request_uri"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
block = &components.Block{
|
block = &components.Block{
|
||||||
Directives: []components.IDirective{
|
Directives: []components.IDirective{
|
||||||
@@ -2116,7 +2109,7 @@ func (w WebsiteService) OperateRedirect(req request.NginxRedirectReq) (err error
|
|||||||
Directives: []components.IDirective{
|
Directives: []components.IDirective{
|
||||||
&components.Directive{
|
&components.Directive{
|
||||||
Name: "return",
|
Name: "return",
|
||||||
Parameters: []string{"301", target},
|
Parameters: []string{req.Redirect, target},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ func (r *Local) Backup(info BackupInfo) error {
|
|||||||
}
|
}
|
||||||
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||||
global.LOG.Infof("start to mysqldump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
global.LOG.Infof("start to mysqldump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
||||||
cmd := exec.Command("docker", "exec", r.ContainerName, "mysqldump", "-uroot", "-p"+r.Password, info.Name)
|
cmd := exec.Command("docker", "exec", r.ContainerName, "mysqldump", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||||
gzipCmd := exec.Command("gzip", "-cf")
|
gzipCmd := exec.Command("gzip", "-cf")
|
||||||
gzipCmd.Stdin, _ = cmd.StdoutPipe()
|
gzipCmd.Stdin, _ = cmd.StdoutPipe()
|
||||||
gzipCmd.Stdout = outfile
|
gzipCmd.Stdout = outfile
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="22" :offset="1" v-loading="loading">
|
<el-col :span="22" :offset="1" v-loading="loading">
|
||||||
<FileRole :mode="mode" @get-mode="getMode"></FileRole>
|
<FileRole :mode="mode" @get-mode="getMode" :key="open.toString()"></FileRole>
|
||||||
<el-form ref="fileForm" label-position="left" :model="addForm" label-width="100px" :rules="rules">
|
<el-form ref="fileForm" label-position="left" :model="addForm" label-width="100px" :rules="rules">
|
||||||
<el-form-item :label="$t('commons.table.user')" prop="user">
|
<el-form-item :label="$t('commons.table.user')" prop="user">
|
||||||
<el-input v-model.trim="addForm.user" />
|
<el-input v-model.trim="addForm.user" />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="22" :offset="1">
|
<el-col :span="22" :offset="1">
|
||||||
<FileRole v-loading="loading" :mode="mode" @get-mode="getMode"></FileRole>
|
<FileRole v-loading="loading" :mode="mode" @get-mode="getMode" :key="open.toString()"></FileRole>
|
||||||
<el-form-item v-if="form.isDir">
|
<el-form-item v-if="form.isDir">
|
||||||
<el-checkbox v-model="form.sub">{{ $t('file.containSub') }}</el-checkbox>
|
<el-checkbox v-model="form.sub">{{ $t('file.containSub') }}</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<el-checkbox v-if="addForm.isDir" v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
|
<el-checkbox v-if="addForm.isDir" v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<FileRole v-if="setRole" :mode="'0755'" @get-mode="getMode"></FileRole>
|
<FileRole v-if="setRole" :mode="'0755'" @get-mode="getMode" :key="open.toString()"></FileRole>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ const loginRules = reactive({
|
|||||||
password: computed(() => [{ required: true, message: i18n.global.t('commons.rule.password'), trigger: 'blur' }]),
|
password: computed(() => [{ required: true, message: i18n.global.t('commons.rule.password'), trigger: 'blur' }]),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let isLoggingIn = false;
|
||||||
const mfaButtonFocused = ref();
|
const mfaButtonFocused = ref();
|
||||||
const mfaLoginForm = reactive({
|
const mfaLoginForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
@@ -223,7 +224,7 @@ function handleCommand(command: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const login = (formEl: FormInstance | undefined) => {
|
const login = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl || isLoggingIn) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
let requestLoginForm = {
|
let requestLoginForm = {
|
||||||
@@ -244,6 +245,7 @@ const login = (formEl: FormInstance | undefined) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
isLoggingIn = true;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await loginApi(requestLoginForm);
|
const res = await loginApi(requestLoginForm);
|
||||||
if (res.code === 406) {
|
if (res.code === 406) {
|
||||||
@@ -274,18 +276,22 @@ const login = (formEl: FormInstance | undefined) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
loginVerify();
|
loginVerify();
|
||||||
} finally {
|
} finally {
|
||||||
|
isLoggingIn = false;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const mfaLogin = async (auto: boolean) => {
|
const mfaLogin = async (auto: boolean) => {
|
||||||
|
if (isLoggingIn) return;
|
||||||
if ((!auto && mfaLoginForm.code) || (auto && mfaLoginForm.code.length === 6)) {
|
if ((!auto && mfaLoginForm.code) || (auto && mfaLoginForm.code.length === 6)) {
|
||||||
|
isLoggingIn = true;
|
||||||
mfaLoginForm.name = loginForm.name;
|
mfaLoginForm.name = loginForm.name;
|
||||||
mfaLoginForm.password = loginForm.password;
|
mfaLoginForm.password = loginForm.password;
|
||||||
const res = await mfaLoginApi(mfaLoginForm);
|
const res = await mfaLoginApi(mfaLoginForm);
|
||||||
if (res.code === 406) {
|
if (res.code === 406) {
|
||||||
errMfaInfo.value = true;
|
errMfaInfo.value = true;
|
||||||
|
isLoggingIn = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
globalStore.setLogStatus(true);
|
globalStore.setLogStatus(true);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="login-backgroud" v-if="isSafety && !isErr && !isNotFound">
|
<div class="login-background" v-if="isSafety && !isErr && !isNotFound">
|
||||||
<div class="login-wrapper">
|
<div class="login-wrapper">
|
||||||
<div :class="screenWidth > 1110 ? 'left inline-block' : ''">
|
<div :class="screenWidth > 1110 ? 'left inline-block' : ''">
|
||||||
<div class="login-title">
|
<div class="login-title">
|
||||||
@@ -100,7 +100,7 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-backgroud {
|
.login-background {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: url(@/assets/images/1panel-login-bg.png) no-repeat,
|
background: url(@/assets/images/1panel-login-bg.png) no-repeat,
|
||||||
radial-gradient(153.25% 257.2% at 118.99% 181.67%, rgba(50, 132, 255, 0.2) 0%, rgba(82, 120, 255, 0) 100%)
|
radial-gradient(153.25% 257.2% at 118.99% 181.67%, rgba(50, 132, 255, 0.2) 0%, rgba(82, 120, 255, 0) 100%)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="login-backgroud">
|
<div class="login-background">
|
||||||
<div class="login-wrapper">
|
<div class="login-wrapper">
|
||||||
<div :class="screenWidth > 1110 ? 'left inline-block' : ''">
|
<div :class="screenWidth > 1110 ? 'left inline-block' : ''">
|
||||||
<div class="login-title">
|
<div class="login-title">
|
||||||
@@ -54,7 +54,7 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-backgroud {
|
.login-background {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: url(@/assets/images/1panel-login-bg.png) no-repeat,
|
background: url(@/assets/images/1panel-login-bg.png) no-repeat,
|
||||||
radial-gradient(153.25% 257.2% at 118.99% 181.67%, rgba(50, 132, 255, 0.2) 0%, rgba(82, 120, 255, 0) 100%)
|
radial-gradient(153.25% 257.2% at 118.99% 181.67%, rgba(50, 132, 255, 0.2) 0%, rgba(82, 120, 255, 0) 100%)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
sonar.projectKey=1Panel-dev_1Panel
|
sonar.projectKey=1Panel-dev_1Panel
|
||||||
sonar.organization=1panel-dev
|
sonar.organization=1panel-dev
|
||||||
|
|
||||||
sonar.exclusions= frontend/src/lang/modules/*
|
sonar.exclusions=frontend/src/lang/modules/*,backend/i18n/lang/*
|
||||||
|
|
||||||
# This is the name and version displayed in the SonarCloud UI.
|
# This is the name and version displayed in the SonarCloud UI.
|
||||||
#sonar.projectName=1Panel
|
#sonar.projectName=1Panel
|
||||||
@@ -12,4 +12,4 @@ sonar.exclusions= frontend/src/lang/modules/*
|
|||||||
#sonar.sources=.
|
#sonar.sources=.
|
||||||
|
|
||||||
# Encoding of the source code. Default is default system encoding
|
# Encoding of the source code. Default is default system encoding
|
||||||
#sonar.sourceEncoding=UTF-8
|
#sonar.sourceEncoding=UTF-8
|
||||||
|
|||||||
Reference in New Issue
Block a user