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 @@ -1121,3 +1121,23 @@ func (b *BaseApi) OperateCrossSiteAccess(c *gin.Context) {
}
helper.Success(c)
}

// @Tags Website
// @Summary Exec Composer
// @Accept json
// @Param request body request.ExecComposerReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /websites/exec/composer [post]
func (b *BaseApi) ExecComposer(c *gin.Context) {
var req request.ExecComposerReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.ExecComposer(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
42 changes: 26 additions & 16 deletions agent/app/dto/request/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,22 @@ type WebsiteDomainDelete struct {
}

type WebsiteHTTPSOp struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Enable bool `json:"enable"`
WebsiteSSLID uint `json:"websiteSSLId"`
Type string `json:"type" validate:"oneof=existed auto manual"`
PrivateKey string `json:"privateKey"`
Certificate string `json:"certificate"`
PrivateKeyPath string `json:"privateKeyPath"`
CertificatePath string `json:"certificatePath"`
ImportType string `json:"importType"`
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
HttpsPorts []int `json:"httpsPorts"`
Http3 bool `json:"http3"`
WebsiteID uint `json:"websiteId" validate:"required"`
Enable bool `json:"enable"`
WebsiteSSLID uint `json:"websiteSSLId"`
Type string `json:"type" validate:"oneof=existed auto manual"`
PrivateKey string `json:"privateKey"`
Certificate string `json:"certificate"`
PrivateKeyPath string `json:"privateKeyPath"`
CertificatePath string `json:"certificatePath"`
ImportType string `json:"importType"`
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
HttpsPorts []int `json:"httpsPorts"`
Http3 bool `json:"http3"`
}

type WebsiteNginxUpdate struct {
Expand Down Expand Up @@ -299,3 +299,13 @@ type CrossSiteAccessOp struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=Enable Disable"`
}

type ExecComposerReq struct {
Command string `json:"command" validate:"required"`
ExtCommand string `json:"extCommand"`
Mirror string `json:"mirror" validate:"required"`
Dir string `json:"dir" validate:"required"`
User string `json:"user" validate:"required"`
WebsiteID uint `json:"websiteID" validate:"required"`
TaskID string `json:"taskID" validate:"required"`
}
68 changes: 58 additions & 10 deletions agent/app/service/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ type IWebsiteService interface {
ChangeDatabase(req request.ChangeDatabase) error

OperateCrossSiteAccess(req request.CrossSiteAccessOp) error

ExecComposer(req request.ExecComposerReq) error
}

func NewIWebsiteService() IWebsiteService {
Expand Down Expand Up @@ -466,15 +468,15 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
website.Protocol = constant.ProtocolHTTPS
website.WebsiteSSLID = create.WebsiteSSLID
appSSLReq := request.WebsiteHTTPSOp{
WebsiteID: website.ID,
Enable: true,
WebsiteSSLID: websiteModel.ID,
Type: "existed",
HttpConfig: "HTTPToHTTPS",
SSLProtocol: []string{"TLSv1.3", "TLSv1.2"},
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
Hsts: true,
HstsIncludeSubDomains: true,
WebsiteID: website.ID,
Enable: true,
WebsiteSSLID: websiteModel.ID,
Type: "existed",
HttpConfig: "HTTPToHTTPS",
SSLProtocol: []string{"TLSv1.3", "TLSv1.2"},
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
Hsts: true,
HstsIncludeSubDomains: true,
}
if err = applySSL(website, *websiteModel, appSSLReq); err != nil {
return err
Expand Down Expand Up @@ -960,7 +962,6 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
if p.Name == "add_header" && len(p.Params) > 0 {
if p.Params[0] == "Strict-Transport-Security" {
res.Hsts = true
//增加HSTS下子域名检查逻辑
if len(p.Params) > 1 {
hstsValue := p.Params[1]
if strings.Contains(hstsValue, "includeSubDomains") {
Expand Down Expand Up @@ -3319,3 +3320,50 @@ func (w WebsiteService) OperateCrossSiteAccess(req request.CrossSiteAccessOp) er
}
return nil
}

func (w WebsiteService) ExecComposer(req request.ExecComposerReq) error {
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
if err != nil {
return err
}
sitePath := GetSitePath(website, SiteDir)
if !strings.Contains(req.Dir, sitePath) {
return buserr.New("ErrWebsiteDir")
}
if !files.NewFileOp().Stat(path.Join(req.Dir, "composer.json")) {
return buserr.New("ErrComposerFileNotFound")
}
if task.CheckResourceTaskIsExecuting(task.TaskExec, req.Command, website.ID) {
return buserr.New("ErrInstallExtension")
}
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(website.RuntimeID))
if err != nil {
return err
}
var command string
if req.Command != "custom" {
command = fmt.Sprintf("%s %s", req.Command, req.ExtCommand)
} else {
command = req.ExtCommand
}
resourceName := fmt.Sprintf("composer %s", command)
composerTask, err := task.NewTaskWithOps(resourceName, task.TaskExec, req.Command, req.TaskID, website.ID)
if err != nil {
return err
}
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*composerTask), cmd.WithTimeout(20*time.Minute))
siteDir, _ := settingRepo.Get(settingRepo.WithByKey("WEBSITE_DIR"))
execDir := strings.ReplaceAll(req.Dir, siteDir.Value, "/www")
composerTask.AddSubTask("", func(t *task.Task) error {
cmdStr := fmt.Sprintf("docker exec -u %s %s sh -c 'composer config -g repo.packagist composer %s && composer %s --working-dir=%s'", req.User, runtime.ContainerName, req.Mirror, command, execDir)
err = cmdMgr.RunBashCf(cmdStr)
if err != nil {
return err
}
return nil
}, nil)
go func() {
_ = composerTask.Execute()
}()
return nil
}
1 change: 1 addition & 0 deletions agent/app/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const (
TaskPush = "TaskPush"
TaskClean = "TaskClean"
TaskHandle = "TaskHandle"
TaskExec = "TaskExec"
)

const (
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'The build directory does not exist'
ErrImageNotExist: 'The operating environment {{ .name }} image does not exist, please re-edit the operating environment'
ErrProxyIsUsed: "Load balancing has been used by reverse proxy, cannot be deleted"
ErrSSLValid: 'Certificate file is abnormal, please check the certificate status!'
ErrWebsiteDir: "Please select a directory within the website directory."
ErrComposerFileNotFound: "composer.json file does not exist"

#ssl
ErrSSLCannotDelete: 'The {{ .name }} certificate is being used by a website and cannot be deleted'
Expand Down Expand Up @@ -328,6 +330,7 @@ SubTask: 'Subtask'
RuntimeExtension: 'Runtime Environment Extension'
TaskIsExecuting: 'Task is running'
CustomAppstore: 'Custom application warehouse'
TaskExec: 'Execute'

# task - ai
OllamaModelPull: 'Pull Ollama model {{ .name }}'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/ja.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'ビルド ディレクトリが存在しません'
ErrImageNotExist: 'オペレーティング環境 {{ .name }} イメージが存在しません。オペレーティング環境を再編集してください'
ErrProxyIsUsed: "ロードバランシングはリバースプロキシによって使用されているため、削除できません"
ErrSSLValid: '証明書ファイルが異常です、証明書の状態を確認してください!'
ErrWebsiteDir: "ウェブサイトディレクトリ内のディレクトリを選択してください。"
ErrComposerFileNotFound: "composer.json ファイルが存在しません"

#ssl
ErrSSLCannotDelete: '{{ .name }} 証明書は Web サイトで使用されているため、削除できません'
Expand Down Expand Up @@ -328,6 +330,7 @@ SubTask: 'サブタスク'
RuntimeExtension: 'ランタイム環境拡張'
TaskIsExecuting: 'タスクは実行中です'
CustomAppstore: 'カスタム アプリケーション ウェアハウス'
TaskExec: '実行'

#task - ai
OllamaModelPull: 'Ollama モデル {{ .name }} をプルします'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/ko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: '빌드 디렉토리가 존재하지 않습니다'
ErrImageNotExist: '운영 환경 {{ .name }} 이미지가 존재하지 않습니다. 운영 환경을 다시 편집하세요.'
ErrProxyIsUsed: "로드 밸런싱이 역방향 프록시에 의해 사용되었으므로 삭제할 수 없습니다"
ErrSSLValid: '인증서 파일에 문제가 있습니다. 인증서 상태를 확인하세요!'
ErrWebsiteDir: "웹사이트 디렉토리 내의 디렉토리를 선택하세요."
ErrComposerFileNotFound: "composer.json 파일이 존재하지 않습니다"

#SSL인증
ErrSSLCannotDelete: '{{ .name }} 인증서는 웹사이트에서 사용 중이므로 삭제할 수 없습니다.'
Expand Down Expand Up @@ -328,6 +330,7 @@ SubTask: '하위 작업'
RuntimeExtension: '런타임 환경 확장'
TaskIsExecuting: '작업이 실행 중입니다'
CustomAppstore: '사용자 정의 애플리케이션 웨어하우스'
TaskExec": '실행'

# 작업 - ai
OllamaModelPull: 'Ollama 모델 {{ .name }}을(를) 끌어오세요'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/ms.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ ErrBuildDirNotFound: 'Direktori binaan tidak wujud'
ErrImageNotExist: 'Imej persekitaran operasi {{ .name }} tidak wujud, sila edit semula persekitaran pengendalian'
ErrProxyIsUsed: "Pengimbang beban telah digunakan oleh pengganti terbalik, tidak boleh dipadamkan"
ErrSSLValid: 'Fail sijil bermasalah, sila periksa status sijil!'
ErrWebsiteDir: "Sila pilih direktori dalam direktori laman web."
ErrComposerFileNotFound: "Fail composer.json tidak wujud"

#ssl
ErrSSLCannotDelete: 'Sijil {{ .name }} sedang digunakan oleh tapak web dan tidak boleh dipadamkan'
Expand Down Expand Up @@ -327,6 +329,7 @@ SubTask: 'Subtugas'
RuntimeExtension: 'Sambungan Persekitaran Runtime'
TaskIsExecuting: 'Tugas sedang berjalan'
CustomAppstore: 'Gudang aplikasi tersuai'
TaskExec: 'Laksanakan'

# tugasan - ai
OllamaModelPull: 'Tarik model Ollama {{ .name }}'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/pt-BR.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'O diretório de compilação não existe'
ErrImageNotExist: 'A imagem do ambiente operacional {{ .name }} não existe, edite novamente o ambiente operacional'
ErrProxyIsUsed: "Balanceamento de carga foi usado por proxy reverso, não pode ser excluído"
ErrSSLValid: 'O arquivo do certificado está anormal, verifique o status do certificado!'
ErrWebsiteDir: "Por favor, selecione um diretório dentro do diretório do site."
ErrComposerFileNotFound: "O arquivo composer.json não existe"

#ssl
ErrSSLCannotDelete: 'O certificado {{ .name }} está sendo usado por um site e não pode ser excluído'
Expand Down Expand Up @@ -328,6 +330,7 @@ SubTask: 'Subtarefa'
RuntimeExtension: 'Extensão do ambiente de tempo de execução'
TaskIsExecuting: 'A tarefa está em execução'
CustomAppstore: 'Armazém de aplicativos personalizados'
TaskExec: 'Executar'

# tarefa - ai
OllamaModelPull: 'Puxar modelo Ollama {{ .name }}'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/ru.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'Каталог сборки не существует'
ErrImageNotExist: 'Образ операционной среды {{ .name }} не существует, пожалуйста, отредактируйте операционную среду заново'
ErrProxyIsUsed: "Балансировка нагрузки используется обратным прокси, невозможно удалить"
ErrSSLValid: 'Файл сертификата аномален, проверьте статус сертификата!'
ErrWebsiteDir: "Пожалуйста, выберите директорию внутри директории сайта."
ErrComposerFileNotFound: "Файл composer.json не существует"

#ssl
ErrSSLCannotDelete: 'Сертификат {{ .name }} используется веб-сайтом и не может быть удален'
Expand Down Expand Up @@ -328,6 +330,7 @@ SubTask: 'Подзадача'
RuntimeExtension: 'Расширение среды выполнения'
TaskIsExecuting: 'Задача выполняется'
CustomAppstore: 'Хранилище пользовательских приложений'
TaskExec: 'Выполнить'

# задача - ай
OllamaModelPull: 'Вытянуть модель Ollama {{ .name }}'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/tr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'Yapı dizini mevcut değil'
ErrImageNotExist: 'İşletim ortamı {{ .name }} image mevcut değil, lütfen işletim ortamını yeniden düzenleyin'
ErrProxyIsUsed: "Yük dengeleme ters proxy tarafından kullanıldı, silinemez"
ErrSSLValid: 'Sertifika dosyası anormal, lütfen sertifika durumunu kontrol edin!'
ErrWebsiteDir: "Lütfen web sitesi dizini içindeki bir dizin seçin."
ErrComposerFileNotFound: "composer.json dosyası mevcut değil"

#ssl
ErrSSLCannotDelete: '{{ .name }} sertifikası bir web sitesi tarafından kullanılıyor ve silinemez'
Expand Down Expand Up @@ -326,6 +328,7 @@ SubTask: 'Alt görev'
RuntimeExtension: 'Çalışma Ortamı Uzantısı'
TaskIsExecuting: 'Görev çalışıyor'
CustomAppstore: 'Özel uygulama deposu'
TaskExec: 'Çalıştır'

# task - ai
OllamaModelPull: 'Ollama modeli {{ .name }} çek'
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/zh-Hant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ ErrBuildDirNotFound: '建置目錄不存在'
ErrImageNotExist: '執行環境{{ .name }} 映像不存在,請重新編輯執行環境'
ErrProxyIsUsed: "負載均衡已被反向代理使用,無法刪除"
ErrSSLValid: '證書文件異常,請檢查證書狀態!'
ErrWebsiteDir: "請選擇網站目錄下的目錄"
ErrComposerFileNotFound: "composer.json 文件不存在"

#ssl
ErrSSLCannotDelete: '{{ .name }} 憑證正在被網站使用,無法刪除'
Expand Down Expand Up @@ -327,6 +329,7 @@ SubTask: '子任務'
RuntimeExtension: '執行環境擴充'
TaskIsExecuting: '任務正在運作'
CustomAppstore: '自訂應用程式倉庫'
TaskExec: '執行'

# task - ai
OllamaModelPull: '拉取 Ollama 模型{{ .name }} '
Expand Down
3 changes: 3 additions & 0 deletions agent/i18n/lang/zh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ ErrBuildDirNotFound: "构建目录不存在"
ErrImageNotExist: "运行环境 {{ .name }} 镜像不存在,请重新编辑运行环境"
ErrProxyIsUsed: "负载均衡已被反向代理使用,无法删除"
ErrSSLValid: '证书文件异常,请检查证书状态!'
ErrWebsiteDir: '请选择网站目录下的目录'
ErrComposerFileNotFound: 'composer.json 文件不存在'

#ssl
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
Expand Down Expand Up @@ -327,6 +329,7 @@ SubTask: "子任务"
RuntimeExtension: "运行环境扩展"
TaskIsExecuting: "任务正在运行"
CustomAppstore: "自定义应用仓库"
TaskExec: "执行"

# task - ai
OllamaModelPull: "拉取 Ollama 模型 {{ .name }} "
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 @@ -86,5 +86,7 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
websiteRouter.POST("/databases", baseApi.ChangeWebsiteDatabase)

websiteRouter.POST("/crosssite", baseApi.OperateCrossSiteAccess)

websiteRouter.POST("/exec/composer", baseApi.ExecComposer)
}
}
10 changes: 10 additions & 0 deletions frontend/src/api/interface/website.ts
Original file line number Diff line number Diff line change
Expand Up @@ -655,4 +655,14 @@ export namespace Website {
websiteID: number;
operation: string;
}

export interface ExecComposer {
websiteID: number;
command: string;
extCommand?: string;
mirror: string;
dir: string;
user: string;
taskID: 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 @@ -347,3 +347,7 @@ export const listCustomRewrite = () => {
export const operateCrossSiteAccess = (req: Website.CrossSiteAccessOp) => {
return http.post(`/websites/crosssite`, req);
};

export const execComposer = (req: Website.ExecComposer) => {
return http.post(`/websites/exec/composer`, req);
};
6 changes: 6 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,12 @@ const message = {
'The time static resources are cached locally in the browser, reducing redundant requests. Users will use the local cache directly before it expires when refreshing the page.',
donotLinkeDB: 'Do Not Link Database',
toWebsiteDir: 'Enter Website Directory',
execParameters: 'Execution Parameters',
extCommand: 'Supplementary Command',
mirror: 'Mirror Source',
execUser: 'Executing User',
execDir: 'Execution Directory',
packagist: 'China Full Mirror',
},
php: {
short_open_tag: 'Short tag support',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lang/modules/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2438,6 +2438,12 @@ const message = {
'静的リソースがブラウザのローカルにキャッシュされる時間、冗長なリクエストを減らします。有効期限前にユーザーがページをリフレッシュすると、ローカルキャッシュが直接使用されます。',
donotLinkeDB: 'データベースをリンクしない',
toWebsiteDir: 'ウェブサイトディレクトリに入る',
execParameters: '実行パラメータ',
extCommand: '補足コマンド',
mirror: 'ミラーソース',
execUser: '実行ユーザー',
execDir: '実行ディレクトリ',
packagist: '中国フルミラー',
},
php: {
short_open_tag: '短いタグサポート',
Expand Down
Loading
Loading