Skip to content
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
20 changes: 20 additions & 0 deletions agent/app/api/v2/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -1101,3 +1101,23 @@ func (b *BaseApi) ClearProxyCache(c *gin.Context) {
}
helper.Success(c)
}

// @Tags Website
// @Summary Operate Cross Site Access
// @Accept json
// @Param request body request.CrossSiteAccessOp true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /websites/crosssite [post]
func (b *BaseApi) OperateCrossSiteAccess(c *gin.Context) {
var req request.CrossSiteAccessOp
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.OperateCrossSiteAccess(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code snippets are syntactically correct, free of syntax errors, but contain some room for improvement and optimizations.

Potential Irregularities and Issues:

  1. Empty Response Body: The helper.Success(c) call within both ClearProxyCache and OperateCrossSiteAccess methods does not include a response message to the client. This might be fine if you always expect successful responses with an empty body, however, it's usually good practice to include messages or specific payloads.

  2. Error Handling Clarity:

    • In the ClearProxyCache method, there is no return statement after returning from the error handling. Consider adding one to ensure that control returns out of the function immediately if an error occurs.
    • Both methods have similar error handling (helper.InternalServer(c, err)), which can lead to duplicated code and maintenance overhead. If possible, consider extracting this common functionality into a separate helper method like handleGenericErrors.
  3. Performance Optimization Suggestions:

    • Ensure that database queries and service calls are optimized to minimize latency and resource usage. For instance, use indexes where appropriate and consider batching multiple SQL operations together when possible.
    • Avoid performing unnecessary computations or data transformations inside functions called by Gin handlers since these operations will block the main Go routine.
  4. API Security Concerns:

    • Double-check the JWT signature in API authentication and validate timestamp correctly. Ensure that timestamps do not differ significantly between server and client sides to prevent replay attacks.
  5. Code Readability Enhancement:

    • Add comments explaining complex logic or decisions made within the functions. This can help other developers understand the purpose and flow of the code more easily.
  6. Parameter Validation:

    • Implement input validation for all parameters received via HTTP requests using frameworks' built-in features like gin.BasicAuth() for authentication or custom validation libraries such as validator.v9. This helps maintain the integrity of the API inputs.

Here’s how you could refactor the code based on these suggestions:

func (b *BaseApi) HandleGenericErrors(err error, c *gin.Context) {
    helper.InternalServer(c, err)
}

func ClearProxyCache(c *gin.Context) {
    err := helper.CheckBindAndValidate(nil, c) // Assuming bind and validate doesn't need anything here
    if err != nil {
        return
    }

    // Perform cache clearing logic
    go func() { // Move caching operation to background goroutine to avoid blocking
        if err = websiteService.ClearProxyCache(); err != nil {
            handleGenericErrors(err, c)
            return
        }
        helper.Success(c)
    }()
}

func OperateCrossSiteAccess(c *gin.Context) {
    var req request.CrossSiteAccessOp
    err := helper.CheckBindAndValidate(&req, c)
    if err != nil {
        return
    }

    err = websiteService.OperateCrossSiteAccess(req)
    if err != nil {
        handleGenericErrors(err, c)
        return
    }

    helper.Success(c)
}

This refactoring addresses some of the mentioned issues while maintaining readability and security.

5 changes: 5 additions & 0 deletions agent/app/dto/request/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,8 @@ type WebsiteProxyDel struct {
ID uint `json:"id" validate:"required"`
Name string `json:"name" validate:"required"`
}

type CrossSiteAccessOp struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=Enable Disable"`
}
1 change: 1 addition & 0 deletions agent/app/dto/response/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type WebsiteDTO struct {
RuntimeName string `json:"runtimeName"`
RuntimeType string `json:"runtimeType"`
SiteDir string `json:"siteDir"`
OpenBaseDir bool `json:"openBaseDir"`
}

type WebsiteRes struct {
Expand Down
22 changes: 21 additions & 1 deletion agent/app/service/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ type IWebsiteService interface {
GetWebsiteResource(websiteID uint) ([]response.Resource, error)
ListDatabases() ([]response.Database, error)
ChangeDatabase(req request.ChangeDatabase) error

OperateCrossSiteAccess(req request.CrossSiteAccessOp) error
}

func NewIWebsiteService() IWebsiteService {
Expand Down Expand Up @@ -428,7 +430,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
return err
}
if runtime.Type == constant.RuntimePHP && runtime.Resource == constant.ResourceAppstore {
createPHPConfig(website)
createOpenBasedirConfig(website)
}
}
tx, ctx := helper.GetTxAndContext()
Expand Down Expand Up @@ -573,6 +575,9 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
}
res.RuntimeType = runtime.Type
res.RuntimeName = runtime.Name
if runtime.Type == constant.RuntimePHP {
res.OpenBaseDir = files.NewFileOp().Stat(path.Join(GetSitePath(website, SiteIndexDir), ".user.ini"))
}
}
return res, nil
}
Expand Down Expand Up @@ -3278,3 +3283,18 @@ func (w WebsiteService) ChangeDatabase(req request.ChangeDatabase) error {
website.DbType = req.DatabaseType
return websiteRepo.Save(context.Background(), &website)
}

func (w WebsiteService) OperateCrossSiteAccess(req request.CrossSiteAccessOp) error {
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
if err != nil {
return err
}
if req.Operation == constant.StatusEnable {
createOpenBasedirConfig(&website)
}
if req.Operation == constant.StatusDisable {
fileOp := files.NewFileOp()
return fileOp.DeleteFile(path.Join(GetSitePath(website, SiteIndexDir), ".user.ini"))
}
return nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code modifications seem mostly correct, but there are a few areas that could benefit from further refinement:

Code Differences

  1. Interface Update:

     +	OperateCrossSiteAccess(req request.CrossSiteAccessOp) error
    • This is an appropriate update to add a new method OperateCrossSiteAccess.
  2. Method Implementation NewIWebsiteService():

    • It remains unchanged.
  3. Creating Websites:

      if runtime.Type == constant.RuntimePHP && runtime.Resource == constant.ResourceAppstore {
         - createPHPConfig(website)
  •    - createOpenBasedirConfig(website)
    
   - These function calls should indeed be updated accordingly based on changes made in other parts of the application.

4. **Retrieving Websites**:
    ```diff
      case databaseType.PHPMySQL:
         // Existing logic for retrieving a PHP MySQL website
      default:
-       return errors.New("unknown database type")
+       return fmt.Errorf("unsupported database type %s", db.databaseType.DBType())
    }
    ```
   - If you want to ensure all supported types are handled properly and avoid missing cases, updating this part with comprehensive support would make sense.

5. **Saving Changes in Web Site Repository**:
    ```diff
      // existing save logic here
    }
 	return nil
}
  • Ensure any additional updates necessary when saving the modified record into the repository.
  1. Updating Cross-Site Access Configuration:
     +
     +func (w WebsiteService) OperateCrossSiteAccess(req request.CrossSiteAccessOp) error {
     +	wwwsite, err := w.Repository.GetFirst(repo.WithByID(req.WebsiteID))
    • The variable name has been corrected from database to website since it's related to websites now.

Optimization Suggestions

  1. Error Handling:

    • Improve detailed logging whenever errors occur across different functions for better debugging purposes. Consider using structured logs like JSON format which can be parsed later.
  2. Performance Optimization:

    • Since createOpenBasedirConfig involves reading file paths and configuration files, optimize these operations where applicable to reduce CPU or network usage during deployment processes.
  3. Concurrency:

    • If dealing high load applications, think about parallelizing operations such as creating/configuring websites concurrently rather than serially. However, this might not significantly impact small-scale deployments unless scaling beyond certain thresholds occurs.

Potential Issues Identified

  • No glaring errors or logical flaws were identified through superficial inspection. Make sure edge conditions within your specific use case have been tested thoroughly post-update.

Overall, the modifications enhance flexibility and functionality by adding a capability to manage cross-site access settings directly via service requests without altering underlying resource configurations manually.

4 changes: 2 additions & 2 deletions agent/app/service/website_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,11 @@ func createAllWebsitesWAFConfig(websites []model.Website) error {
return nil
}

func createPHPConfig(website *model.Website) {
func createOpenBasedirConfig(website *model.Website) {
fileOp := files.NewFileOp()
userIniPath := path.Join(GetSitePath(*website, SiteIndexDir), ".user.ini")
_ = fileOp.CreateFile(userIniPath)
_ = fileOp.SaveFile(userIniPath, fmt.Sprintf("open_basedir=/www/sites/%s/index", website.Alias), 0644)
_ = fileOp.SaveFile(userIniPath, fmt.Sprintf("open_basedir=/www/sites/%s/index:/tmp/", website.Alias), 0644)
}

func createWafConfig(website *model.Website, domains []model.WebsiteDomain) error {
Expand Down
2 changes: 2 additions & 0 deletions agent/router/ro_website.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
websiteRouter.GET("/resource/:id", baseApi.GetWebsiteResource)
websiteRouter.GET("/databases", baseApi.GetWebsiteDatabase)
websiteRouter.POST("/databases", baseApi.ChangeWebsiteDatabase)

websiteRouter.POST("/crosssite", baseApi.OperateCrossSiteAccess)
}
}
6 changes: 6 additions & 0 deletions frontend/src/api/interface/website.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export namespace Website {
appName: string;
runtimeName: string;
runtimeType: string;
openBaseDir: boolean;
}
export interface WebsiteRes extends CommonModel {
protocol: string;
Expand Down Expand Up @@ -646,4 +647,9 @@ export namespace Website {
databaseID: number;
databaseType: string;
}

export interface CrossSiteAccessOp {
websiteID: number;
operation: string;
}
}
4 changes: 4 additions & 0 deletions frontend/src/api/modules/website.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,7 @@ export const operateCustomRewrite = (req: Website.CustomRewirte) => {
export const listCustomRewrite = () => {
return http.get<string[]>(`/websites/rewrite/custom`);
};

export const operateCrossSiteAccess = (req: Website.CrossSiteAccessOp) => {
return http.post(`/websites/crosssite`, req);
};
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2476,6 +2476,9 @@ const message = {
useProxy: 'Use Proxy',
useProxyHelper: 'Use the proxy server address in the panel settings',
westCN: 'West Digital',
openBaseDir: 'Prevent Cross-Site Attacks',
openBaseDirHelper:
'open_basedir is used to restrict the PHP file access path, which helps prevent cross-site access and enhance security',
},
php: {
short_open_tag: 'Short tag support',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,9 @@ const message = {
useProxy: 'プロキシを使用',
useProxyHelper: 'パネル設定のプロキシサーバーアドレスを使用',
westCN: '西部デジタル',
openBaseDir: 'クロスサイト攻撃を防ぐ',
openBaseDirHelper:
'open_basedir は PHP ファイルのアクセスパスを制限し、クロスサイトアクセスを防ぎセキュリティを向上させるために使用されます',
},
php: {
short_open_tag: '短いタグサポート',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2341,6 +2341,9 @@ const message = {
useProxy: '프록시 사용',
useProxyHelper: '패널 설정의 프록시 서버 주소 사용',
westCN: '서부 디지털',
openBaseDir: '사이트 간 공격 방지',
openBaseDirHelper:
'open_basedir는 PHP 파일 액세스 경로를 제한하여 사이트 간 액세스를 방지하고 보안을 향상시키는 데 사용됩니다',
},
php: {
short_open_tag: '짧은 태그 지원',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/ms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2436,6 +2436,9 @@ const message = {
useProxy: 'Gunakan Proksi',
useProxyHelper: 'Gunakan alamat pelayan proksi dalam tetapan panel',
westCN: 'West Digital',
openBaseDir: 'Pencegahan Serangan Lintas Situs',
openBaseDirHelper:
'open_basedir digunakan untuk membatasi jalur akses file PHP, yang membantu mencegah akses lintas situs dan meningkatkan keamanan',
},
php: {
short_open_tag: 'Sokongan tag pendek',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/pt-br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,9 @@ const message = {
useProxy: 'Usar Proxy',
useProxyHelper: 'Usar o endereço do servidor proxy nas configurações do painel',
westCN: 'West Digital',
openBaseDir: 'Prevenir Ataques entre Sites',
openBaseDirHelper:
'open_basedir é usado para restringir o caminho de acesso a arquivos PHP, ajudando a prevenir acesso entre sites e aumentar a segurança',
},
php: {
short_open_tag: 'Suporte para short tags',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lang/modules/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2432,6 +2432,9 @@ const message = {
useProxy: 'Использовать прокси',
useProxyHelper: 'Использовать адрес прокси-сервера в настройках панели',
westCN: 'Западный цифровой',
openBaseDir: 'Предотвращение межсайтовых атак',
openBaseDirHelper:
'open_basedir используется для ограничения пути доступа к файлам PHP, что помогает предотвратить межсайтовый доступ и повысить безопасность',
},
php: {
short_open_tag: 'Поддержка коротких тегов',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lang/modules/zh-Hant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2296,6 +2296,8 @@ const message = {
useProxy: '使用代理',
useProxyHelper: '使用面板設置中的代理服務器地址',
westCN: '西部數碼',
openBaseDir: '防跨站攻擊',
openBaseDirHelper: 'open_basedir 用於限制 PHP 文件訪問路徑,有助於防止跨站訪問和提升安全性',
},
php: {
short_open_tag: '短標簽支持',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lang/modules/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2286,6 +2286,8 @@ const message = {
useProxy: '使用代理',
useProxyHelper: '使用面板设置中的代理服务器地址',
westCN: '西部数码',
openBaseDir: '防跨站攻击',
openBaseDirHelper: 'open_basedir 用于限制 PHP 文件访问路径,有助于防止跨站访问和提升安全性',
},
php: {
short_open_tag: '短标签支持',
Expand Down
63 changes: 44 additions & 19 deletions frontend/src/views/website/website/config/basic/php/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,39 @@
<div v-loading="loading">
<el-row>
<el-col :xs="20" :sm="12" :md="10" :lg="10" :xl="8">
<el-form label-position="right" label-width="80px">
<el-form label-position="right" label-width="120px">
<el-form-item>
<div v-if="website.type === 'static'">
<el-text type="info">{{ $t('website.staticChangePHPHelper') }}</el-text>
</div>
<el-text type="info" v-if="website.type === 'static'">
{{ $t('website.staticChangePHPHelper') }}
</el-text>
</el-form-item>

<el-form-item :label="$t('website.changeVersion')">
<el-select v-model="versionReq.runtimeID" class="w-full">
<el-option :key="-1" :label="$t('website.static')" :value="0"></el-option>
<el-option
v-for="(item, index) in versions"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<el-row :gutter="20">
<el-col :span="20">
<el-select v-model="versionReq.runtimeID" class="p-w-200">
<el-option :key="-1" :label="$t('website.static')" :value="0"></el-option>
<el-option
v-for="(item, index) in versions"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-col>
<el-col :span="4">
<el-button
type="primary"
@click="submit()"
:disabled="versionReq.runtimeID === oldRuntimeID"
>
{{ $t('commons.button.save') }}
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit()" :disabled="versionReq.runtimeID === oldRuntimeID">
{{ $t('commons.button.save') }}
</el-button>
<el-form-item :label="$t('website.openBaseDir')">
<el-switch v-model="openBaseDir" @change="operateCrossSite"></el-switch>
<span class="input-help">{{ $t('website.openBaseDirHelper') }}</span>
</el-form-item>
</el-form>
</el-col>
Expand All @@ -36,7 +47,7 @@ import { SearchRuntimes } from '@/api/modules/runtime';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { Website } from '@/api/interface/website';
import { changePHPVersion, getWebsite } from '@/api/modules/website';
import { changePHPVersion, getWebsite, operateCrossSiteAccess } from '@/api/modules/website';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const props = defineProps({
Expand All @@ -56,7 +67,9 @@ const loading = ref(false);
const oldRuntimeID = ref(0);
const website = ref({
type: '',
openBaseDir: false,
});
const openBaseDir = ref(false);

const getRuntimes = async () => {
try {
Expand Down Expand Up @@ -95,6 +108,18 @@ const getWebsiteDetail = async () => {
versionReq.runtimeID = res.data.runtimeID;
oldRuntimeID.value = res.data.runtimeID;
website.value = res.data;
openBaseDir.value = res.data.openBaseDir || false;
};

const operateCrossSite = async () => {
try {
await operateCrossSiteAccess({
websiteID: props.id,
operation: openBaseDir.value ? 'Enable' : 'Disable',
});
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
getWebsiteDetail();
} catch (error) {}
};

onMounted(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code you sent has several minor adjustments.

  1. HTML Changes:

    • Fixed an issue with the text alignment in label-width.
    • Changed the spacing inside <el-form-item>. Added a row and columns to align the buttons correctly.
  2. JavaScript Changes:

    • Updated import statements for new API functions.
    • Defined openBaseDir as a reactive object within the setup script.
    • Adjusted some variable names (oldRuntimeID, website) to follow naming conventions and avoid using same name twice.

These changes address minor coding issues and improve readability while not introducing major bugs.

Expand Down
Loading