Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PHP 网站增加禁用函数设置 #1125

Merged
merged 1 commit into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions backend/app/dto/request/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ type WebsiteDefaultUpdate struct {
}

type WebsitePHPConfigUpdate struct {
ID uint `json:"id" validate:"required"`
Params map[string]string `json:"params" validate:"required"`
ID uint `json:"id" validate:"required"`
Params map[string]string `json:"params"`
Scope string `json:"scope" validate:"required"`
DisableFunctions []string `json:"disableFunctions"`
}

type WebsitePHPFileUpdate struct {
Expand Down
3 changes: 2 additions & 1 deletion backend/app/dto/response/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ type WebsiteLog struct {
}

type PHPConfig struct {
Params map[string]string `json:"params"`
Params map[string]string `json:"params"`
DisableFunctions []string `json:"disableFunctions"`
}

type NginxRewriteRes struct {
Expand Down
71 changes: 58 additions & 13 deletions backend/app/service/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
"golang.org/x/crypto/bcrypt"
"gopkg.in/ini.v1"
"gorm.io/gorm"
"os"
"path"
Expand Down Expand Up @@ -1009,7 +1010,23 @@ func (w WebsiteService) GetPHPConfig(id uint) (*response.PHPConfig, error) {
params[matches[1]] = matches[2]
}
}
return &response.PHPConfig{Params: params}, nil
cfg, err := ini.Load(phpConfigPath)
if err != nil {
return nil, err
}
phpConfig, err := cfg.GetSection("PHP")
if err != nil {
return nil, err
}
disableFunctionStr := phpConfig.Key("disable_functions").Value()
res := &response.PHPConfig{Params: params}
if disableFunctionStr != "" {
disableFunctions := strings.Split(disableFunctionStr, ",")
if len(disableFunctions) > 0 {
res.DisableFunctions = disableFunctions
}
}
return res, nil
}

func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err error) {
Expand All @@ -1033,23 +1050,50 @@ func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err
defer configFile.Close()

contentBytes, err := fileOp.GetContent(phpConfigPath)
content := string(contentBytes)
lines := strings.Split(content, "\n")
for i, line := range lines {
if strings.HasPrefix(line, ";") {
continue
}
for key, value := range req.Params {
pattern := "^" + regexp.QuoteMeta(key) + "\\s*=\\s*.*$"
if matched, _ := regexp.MatchString(pattern, line); matched {
lines[i] = key + " = " + value
if err != nil {
return err
}

if req.Scope == "params" {
content := string(contentBytes)
lines := strings.Split(content, "\n")
for i, line := range lines {
if strings.HasPrefix(line, ";") {
continue
}
for key, value := range req.Params {
pattern := "^" + regexp.QuoteMeta(key) + "\\s*=\\s*.*$"
if matched, _ := regexp.MatchString(pattern, line); matched {
lines[i] = key + " = " + value
}
}
}
updatedContent := strings.Join(lines, "\n")
if err := fileOp.WriteFile(phpConfigPath, strings.NewReader(updatedContent), 0755); err != nil {
return err
}
}
updatedContent := strings.Join(lines, "\n")
if err := fileOp.WriteFile(phpConfigPath, strings.NewReader(updatedContent), 0755); err != nil {

cfg, err := ini.Load(phpConfigPath)
if err != nil {
return err
}
phpConfig, err := cfg.GetSection("PHP")
if err != nil {
return err
}
if req.Scope == "disable_functions" {
disable := phpConfig.Key("disable_functions")
disable.SetValue(strings.Join(req.DisableFunctions, ","))
if err = cfg.SaveTo(phpConfigPath); err != nil {
return err
}
}
if req.Scope == "uploadSize" {
postMaxSize := phpConfig.Key("post_max_size")
postMaxSize.SetValue("")
}

appInstallReq := request.AppInstalledOperate{
InstallId: appInstall.ID,
Operate: constant.Restart,
Expand All @@ -1058,6 +1102,7 @@ func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err
_ = fileOp.WriteFile(phpConfigPath, strings.NewReader(string(contentBytes)), 0755)
return err
}

return nil
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ declare module 'vue' {
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage'];
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'];
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMain: typeof import('element-plus/es')['ElMain'];
ElMenu: typeof import('element-plus/es')['ElMenu']
Expand Down Expand Up @@ -76,7 +76,7 @@ declare module 'vue' {
FileRole: typeof import('./src/components/file-role/index.vue')['default']
FormButton: typeof import('./src/components/layout-content/form-button.vue')['default']
Group: typeof import('./src/components/group/index.vue')['default']
InfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'];
InfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
LayoutContent: typeof import('./src/components/layout-content/index.vue')['default']
Line: typeof import('./src/components/v-charts/components/Line.vue')['default']
Loading: typeof import('element-plus/es')['ElLoadingDirective']
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/api/interface/website.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,14 @@ export namespace Website {

export interface PHPConfig {
params: any;
disableFunctions: string[];
}

export interface PHPConfigUpdate {
id: number;
params: any;
params?: any;
disableFunctions?: string[];
scope: string;
}

export interface PHPUpdate {
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/global/form-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,19 @@ const checkConatinerName = (rule: any, value: any, callback: any) => {
}
};

const checkDisableFunctions = (rule: any, value: any, callback: any) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.disableFunction')));
} else {
const reg = /^[a-zA-Z,]+$/;
if (!reg.test(value) && value !== '') {
callback(new Error(i18n.global.t('commons.rule.disableFunction')));
} else {
callback();
}
}
};

interface CommonRule {
requiredInput: FormItemRule;
requiredSelect: FormItemRule;
Expand All @@ -300,6 +313,7 @@ interface CommonRule {
nginxDoc: FormItemRule;
appName: FormItemRule;
containerName: FormItemRule;
disabledFunctions: FormItemRule;

paramCommon: FormItemRule;
paramComplexity: FormItemRule;
Expand Down Expand Up @@ -446,4 +460,9 @@ export const Rules: CommonRule = {
trigger: 'blur',
validator: checkConatinerName,
},
disabledFunctions: {
required: true,
trigger: 'blur',
validator: checkDisableFunctions,
},
};
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ const message = {
nginxDoc: 'Only supports English case, numbers, and .',
appName: 'Support English, numbers, - and _, length 2-30, and cannot start and end with -_',
conatinerName: 'Supports letters, numbers, underscores, hyphens and dots, cannot end with hyphen- or dot.',
disableFunction: 'Only support letters and,',
},
res: {
paramError: 'The request failed, please try again later!',
Expand Down Expand Up @@ -1384,6 +1385,8 @@ const message = {
cgi_fix_pathinfo: 'Whether to open pathinfo',
date_timezone: 'Time zone',
second: 'Second',
disableFunction: 'Disable function',
disableFunctionHelper: 'Enter the function to be disabled, such as exec, please use multiple, split',
},
nginx: {
serverNamesHashBucketSizeHelper: 'The hash table size of the server name',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const message = {
nginxDoc: '仅支持英文大小写,数字,和.',
appName: '支持英文、数字、-和_,长度2-30,并且不能以-_开头和结尾',
conatinerName: '支持字母、数字、下划线、连字符和点,不能以连字符-或点.结尾',
disableFunction: '仅支持字母和,',
},
res: {
paramError: '请求失败,请稍后重试!',
Expand Down Expand Up @@ -1365,6 +1366,8 @@ const message = {
cgi_fix_pathinfo: '是否开启pathinfo',
date_timezone: '时区',
second: '秒',
disableFunction: '禁用函数',
disableFunctionHelper: '输入要禁用的函数,例如exec,多个请用,分割',
},
nginx: {
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const submit = async () => {
display_errors: form.display_errors,
};
loading.value = true;
UpdatePHPConfig({ id: id.value, params: params })
UpdatePHPConfig({ id: id.value, params: params, scope: 'params' })
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
})
Expand Down
142 changes: 142 additions & 0 deletions frontend/src/views/website/website/config/php/function/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<template>
<div>
<el-row>
<el-col :xs="20" :sm="12" :md="10" :lg="10" :xl="8" :offset="1">
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item prop="funcs">
<el-input
type="text"
v-model="form.funcs"
label="value"
:placeholder="$t('php.disableFunctionHelper')"
/>
</el-form-item>
</el-form>
<ComplexTable :data="data" v-loading="loading">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openCreate(formRef)">
{{ $t('commons.button.add') }}
</el-button>
</template>
<el-table-column :label="$t('commons.table.name')" prop="func"></el-table-column>
<el-table-column :label="$t('commons.table.operate')">
<template #default="{ $index }">
<el-button link type="primary" @click="remove($index)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
</el-table-column>
</ComplexTable>
</el-col>
</el-row>
<ConfirmDialog ref="confirmDialogRef" @confirm="submit(false, [''])"></ConfirmDialog>
</div>
</template>
<script setup lang="ts">
import { GetPHPConfig, UpdatePHPConfig } from '@/api/modules/website';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { onMounted, reactive } from 'vue';
import { computed, ref } from 'vue';

const props = defineProps({
id: {
type: Number,
default: 0,
},
});

const rules = reactive({
funcs: [Rules.requiredInput, Rules.disabledFunctions],
});

const websiteID = computed(() => {
return props.id;
});
const formRef = ref();
const loading = ref(false);
const form = ref({
funcs: '',
});
const data = ref([]);
const confirmDialogRef = ref();

const search = () => {
loading.value = true;
GetPHPConfig(websiteID.value)
.then((res) => {
const functions = res.data.disableFunctions || [];
if (functions.length > 0) {
functions.forEach((value: string) => {
data.value.push({
func: value,
});
});
}
})
.finally(() => {
loading.value = false;
});
};

const openCreate = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let params = {
header: i18n.global.t('database.confChange'),
operationInfo: i18n.global.t('database.restartNowHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(params);
});
};

const remove = async (index: number) => {
ElMessageBox.confirm(i18n.global.t('commons.msg.delete'), i18n.global.t('commons.msg.deleteTitle'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
})
.then(() => {
const copyList = data.value.concat();
copyList.splice(index, 1);
const funcArray: string[] = [];
copyList.forEach((d) => {
funcArray.push(d.func);
});
submit(true, funcArray);
})
.catch(() => {});
};

const submit = async (del: boolean, funcArray: string[]) => {
let disableFunctions = [];
if (del) {
disableFunctions = funcArray;
} else {
disableFunctions = form.value.funcs.split(',');
data.value.forEach((d) => {
disableFunctions.push(d.func);
});
}

loading.value = true;
UpdatePHPConfig({ scope: 'disable_functions', id: websiteID.value, disableFunctions: disableFunctions })
.then(() => {
form.value.funcs = '';
data.value = [];
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
search();
})
.finally(() => {
loading.value = false;
});
};

onMounted(() => {
search();
});
</script>
Loading