feat: 修改证书 账号等删除校验

This commit is contained in:
zhengkunwang223 2022-12-05 15:50:53 +08:00 committed by zhengkunwang223
parent 98fd3d3e95
commit c9ff245222
19 changed files with 208 additions and 113 deletions

View File

@ -4,7 +4,7 @@ type WebsiteAcmeAccount struct {
BaseModel
Email string `gorm:"type:varchar(256);not null" json:"email"`
URL string `gorm:"type:varchar(256);not null" json:"url"`
PrivateKey string `gorm:"type:longtext;not null" json:"_"`
PrivateKey string `gorm:"type:longtext;not null" json:"-"`
}
func (w WebsiteAcmeAccount) TableName() string {

View File

@ -4,18 +4,19 @@ import "time"
type WebSiteSSL struct {
BaseModel
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
Pem string `gorm:"type:longtext;not null" json:"pem"`
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
Type string `gorm:"type:varchar(64);not null" json:"type"`
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
ExpireDate time.Time `json:"expireDate"`
StartDate time.Time `json:"startDate"`
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
Pem string `gorm:"type:longtext;not null" json:"pem"`
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
Type string `gorm:"type:varchar(64);not null" json:"type"`
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount"`
ExpireDate time.Time `json:"expireDate"`
StartDate time.Time `json:"startDate"`
}
func (w WebSiteSSL) TableName() string {

View File

@ -8,28 +8,51 @@ import (
"gorm.io/gorm/clause"
)
type IWebsiteRepo interface {
WithAppInstallId(appInstallId uint) DBOption
WithDomain(domain string) DBOption
WithAlias(alias string) DBOption
WithWebsiteSSLID(sslId uint) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.WebSite, error)
GetFirst(opts ...DBOption) (model.WebSite, error)
GetBy(opts ...DBOption) ([]model.WebSite, error)
Save(ctx context.Context, app *model.WebSite) error
DeleteBy(ctx context.Context, opts ...DBOption) error
Create(ctx context.Context, app *model.WebSite) error
}
func NewIWebsiteRepo() IWebsiteRepo {
return &WebSiteRepo{}
}
type WebSiteRepo struct {
}
func (w WebSiteRepo) WithAppInstallId(appInstallId uint) DBOption {
func (w *WebSiteRepo) WithAppInstallId(appInstallId uint) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("app_install_id = ?", appInstallId)
}
}
func (w WebSiteRepo) WithDomain(domain string) DBOption {
func (w *WebSiteRepo) WithDomain(domain string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("primary_domain = ?", domain)
}
}
func (w WebSiteRepo) WithAlias(alias string) DBOption {
func (w *WebSiteRepo) WithAlias(alias string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("alias = ?", alias)
}
}
func (w WebSiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSite, error) {
func (w *WebSiteRepo) WithWebsiteSSLID(sslId uint) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("web_site_ssl_id = ?", sslId)
}
}
func (w *WebSiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSite, error) {
var websites []model.WebSite
db := getDb(opts...).Model(&model.WebSite{})
count := int64(0)
@ -38,7 +61,7 @@ func (w WebSiteRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebS
return count, websites, err
}
func (w WebSiteRepo) GetFirst(opts ...DBOption) (model.WebSite, error) {
func (w *WebSiteRepo) GetFirst(opts ...DBOption) (model.WebSite, error) {
var website model.WebSite
db := getDb(opts...).Model(&model.WebSite{})
if err := db.Preload("Domains").First(&website).Error; err != nil {
@ -47,7 +70,7 @@ func (w WebSiteRepo) GetFirst(opts ...DBOption) (model.WebSite, error) {
return website, nil
}
func (w WebSiteRepo) GetBy(opts ...DBOption) ([]model.WebSite, error) {
func (w *WebSiteRepo) GetBy(opts ...DBOption) ([]model.WebSite, error) {
var websites []model.WebSite
db := getDb(opts...).Model(&model.WebSite{})
if err := db.Find(&websites).Error; err != nil {
@ -56,14 +79,14 @@ func (w WebSiteRepo) GetBy(opts ...DBOption) ([]model.WebSite, error) {
return websites, nil
}
func (w WebSiteRepo) Create(ctx context.Context, app *model.WebSite) error {
func (w *WebSiteRepo) Create(ctx context.Context, app *model.WebSite) error {
return getTx(ctx).Omit(clause.Associations).Create(app).Error
}
func (w WebSiteRepo) Save(ctx context.Context, app *model.WebSite) error {
func (w *WebSiteRepo) Save(ctx context.Context, app *model.WebSite) error {
return getTx(ctx).Omit(clause.Associations).Save(app).Error
}
func (w WebSiteRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
func (w *WebSiteRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.WebSite{}).Error
}

View File

@ -2,10 +2,22 @@ package repo
import "github.com/1Panel-dev/1Panel/backend/app/model"
type IAcmeAccountRepo interface {
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteAcmeAccount, error)
GetFirst(opts ...DBOption) (model.WebsiteAcmeAccount, error)
Create(account model.WebsiteAcmeAccount) error
Save(account model.WebsiteAcmeAccount) error
DeleteBy(opts ...DBOption) error
}
func NewIAcmeAccountRepo() IAcmeAccountRepo {
return &WebsiteAcmeAccountRepo{}
}
type WebsiteAcmeAccountRepo struct {
}
func (w WebsiteAcmeAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteAcmeAccount, error) {
func (w *WebsiteAcmeAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteAcmeAccount, error) {
var accounts []model.WebsiteAcmeAccount
db := getDb(opts...).Model(&model.WebsiteAcmeAccount{})
count := int64(0)
@ -14,7 +26,7 @@ func (w WebsiteAcmeAccountRepo) Page(page, size int, opts ...DBOption) (int64, [
return count, accounts, err
}
func (w WebsiteAcmeAccountRepo) GetFirst(opts ...DBOption) (model.WebsiteAcmeAccount, error) {
func (w *WebsiteAcmeAccountRepo) GetFirst(opts ...DBOption) (model.WebsiteAcmeAccount, error) {
var account model.WebsiteAcmeAccount
db := getDb(opts...).Model(&model.WebsiteAcmeAccount{})
if err := db.First(&account).Error; err != nil {
@ -23,14 +35,14 @@ func (w WebsiteAcmeAccountRepo) GetFirst(opts ...DBOption) (model.WebsiteAcmeAcc
return account, nil
}
func (w WebsiteAcmeAccountRepo) Create(account model.WebsiteAcmeAccount) error {
func (w *WebsiteAcmeAccountRepo) Create(account model.WebsiteAcmeAccount) error {
return getDb().Create(&account).Error
}
func (w WebsiteAcmeAccountRepo) Save(account model.WebsiteAcmeAccount) error {
func (w *WebsiteAcmeAccountRepo) Save(account model.WebsiteAcmeAccount) error {
return getDb().Save(&account).Error
}
func (w WebsiteAcmeAccountRepo) DeleteBy(opts ...DBOption) error {
func (w *WebsiteAcmeAccountRepo) DeleteBy(opts ...DBOption) error {
return getDb(opts...).Debug().Delete(&model.WebsiteAcmeAccount{}).Error
}

View File

@ -6,28 +6,56 @@ import (
"gorm.io/gorm"
)
func NewISSLRepo() ISSLRepo {
return &WebsiteSSLRepo{}
}
type ISSLRepo interface {
WithByAlias(alias string) DBOption
WithByAcmeAccountId(acmeAccountId uint) DBOption
WithByDnsAccountId(dnsAccountId uint) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.WebSiteSSL, error)
GetFirst(opts ...DBOption) (model.WebSiteSSL, error)
List(opts ...DBOption) ([]model.WebSiteSSL, error)
Create(ctx context.Context, ssl *model.WebSiteSSL) error
Save(ssl model.WebSiteSSL) error
DeleteBy(opts ...DBOption) error
}
type WebsiteSSLRepo struct {
}
func (w WebsiteSSLRepo) ByAlias(alias string) DBOption {
func (w WebsiteSSLRepo) WithByAlias(alias string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("alias = ?", alias)
}
}
func (w WebsiteSSLRepo) WithByAcmeAccountId(acmeAccountId uint) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("acme_account_id = ?", acmeAccountId)
}
}
func (w WebsiteSSLRepo) WithByDnsAccountId(dnsAccountId uint) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("dns_account_id = ?", dnsAccountId)
}
}
func (w WebsiteSSLRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSiteSSL, error) {
var sslList []model.WebSiteSSL
db := getDb(opts...).Model(&model.WebSiteSSL{})
count := int64(0)
db = db.Count(&count)
err := db.Debug().Limit(size).Offset(size * (page - 1)).Find(&sslList).Error
err := db.Limit(size).Offset(size * (page - 1)).Preload("AcmeAccount").Find(&sslList).Error
return count, sslList, err
}
func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebSiteSSL, error) {
var website model.WebSiteSSL
db := getDb(opts...).Model(&model.WebSiteSSL{})
if err := db.First(&website).Error; err != nil {
if err := db.Preload("AcmeAccount").First(&website).Error; err != nil {
return website, err
}
return website, nil
@ -36,7 +64,7 @@ func (w WebsiteSSLRepo) GetFirst(opts ...DBOption) (model.WebSiteSSL, error) {
func (w WebsiteSSLRepo) List(opts ...DBOption) ([]model.WebSiteSSL, error) {
var websites []model.WebSiteSSL
db := getDb(opts...).Model(&model.WebSiteSSL{})
if err := db.Find(&websites).Error; err != nil {
if err := db.Preload("AcmeAccount").Find(&websites).Error; err != nil {
return websites, err
}
return websites, nil

View File

@ -66,12 +66,12 @@ var (
settingRepo = repo.RepoGroupApp.SettingRepo
backupRepo = repo.RepoGroupApp.BackupRepo
websiteRepo = repo.RepoGroupApp.WebSiteRepo
websiteRepo = repo.NewIWebsiteRepo()
websiteGroupRepo = repo.RepoGroupApp.WebSiteGroupRepo
websiteDomainRepo = repo.RepoGroupApp.WebSiteDomainRepo
websiteDnsRepo = repo.RepoGroupApp.WebsiteDnsAccountRepo
websiteSSLRepo = repo.RepoGroupApp.WebsiteSSLRepo
websiteAcmeRepo = repo.RepoGroupApp.WebsiteAcmeAccountRepo
websiteSSLRepo = repo.NewISSLRepo()
websiteAcmeRepo = repo.NewIAcmeAccountRepo()
logRepo = repo.RepoGroupApp.LogRepo
)

View File

@ -3,6 +3,8 @@ package service
import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
)
@ -37,5 +39,8 @@ func (w WebSiteAcmeAccountService) Create(create dto.WebsiteAcmeAccountCreate) (
}
func (w WebSiteAcmeAccountService) Delete(id uint) error {
if ssls, _ := websiteSSLRepo.List(websiteSSLRepo.WithByAcmeAccountId(id)); len(ssls) > 0 {
return buserr.New(constant.ErrAccountCannotDelete)
}
return websiteAcmeRepo.DeleteBy(commonRepo.WithByID(id))
}

View File

@ -3,6 +3,8 @@ package service
import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"gopkg.in/square/go-jose.v2/json"
)
@ -24,7 +26,6 @@ func (w WebSiteDnsAccountService) Page(search dto.PageInfo) (int64, []dto.Websit
}
func (w WebSiteDnsAccountService) Create(create dto.WebsiteDnsAccountCreate) (dto.WebsiteDnsAccountCreate, error) {
authorization, err := json.Marshal(create.Authorization)
if err != nil {
return dto.WebsiteDnsAccountCreate{}, err
@ -42,7 +43,6 @@ func (w WebSiteDnsAccountService) Create(create dto.WebsiteDnsAccountCreate) (dt
}
func (w WebSiteDnsAccountService) Update(update dto.WebsiteDnsAccountUpdate) (dto.WebsiteDnsAccountUpdate, error) {
authorization, err := json.Marshal(update.Authorization)
if err != nil {
return dto.WebsiteDnsAccountUpdate{}, err
@ -63,5 +63,8 @@ func (w WebSiteDnsAccountService) Update(update dto.WebsiteDnsAccountUpdate) (dt
}
func (w WebSiteDnsAccountService) Delete(id uint) error {
if ssls, _ := websiteSSLRepo.List(websiteSSLRepo.WithByDnsAccountId(id)); len(ssls) > 0 {
return buserr.New(constant.ErrAccountCannotDelete)
}
return websiteDnsRepo.DeleteBy(commonRepo.WithByID(id))
}

View File

@ -6,6 +6,7 @@ import (
"encoding/pem"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
"path"
@ -209,5 +210,8 @@ func (w WebSiteSSLService) GetWebsiteSSL(websiteId uint) (dto.WebsiteSSLDTO, err
}
func (w WebSiteSSLService) Delete(id uint) error {
if websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(id)); len(websites) > 0 {
return buserr.New(constant.ErrSSLCannotDelete)
}
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
}

View File

@ -60,3 +60,9 @@ var (
ErrDomainIsExist = "ErrDomainIsExist"
ErrAliasIsExist = "ErrAliasIsExist"
)
//ssl
var (
ErrSSLCannotDelete = "ErrSSLCannotDelete"
ErrAccountCannotDelete = "ErrAccountCannotDelete"
)

View File

@ -29,4 +29,8 @@ ErrFileToLarge: "file is too large"
#website
ErrDomainIsExist: "Domain is already exist"
ErrAliasIsExist: "Alias is already exist"
ErrAliasIsExist: "Alias is already exist"
#ssl
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
ErrAccountCannotDelete: "The certificate associated with the account cannot be deleted"

View File

@ -22,11 +22,14 @@ ErrAppLimit: "应用超出安装数量限制"
ErrAppRequired: "请先安装 {{ .detail }} 应用"
ErrNotInstall: "应用未安装"
#file
ErrFileCanNotRead: "文件不可读"
ErrFileToLarge: "文件超过10M,无法打开"
#website
ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代号已存在"
ErrAliasIsExist: "代号已存在"
#ssl
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
ErrAccountCannotDelete: "账号关联证书,无法删除"

View File

@ -867,4 +867,9 @@ export default {
waiting: '驻留进程(Waiting)',
status: '负载状态',
},
ssl: {
provider: '类型',
manualCreate: '手动创建',
acmeAccount: 'Acme 账号',
},
};

View File

@ -56,7 +56,7 @@
<el-icon v-if="row.status === 'Installing'" class="is-loading">
<Loading />
</el-icon>
{{ row.status }}
<Status :status="row.status"></Status>
</div>
</template>
</el-table-column>
@ -129,6 +129,7 @@ import Backups from './backups.vue';
import AppResources from './check/index.vue';
import { App } from '@/api/interface/app';
import { useDeleteData } from '@/hooks/use-delete-data';
import Status from '@/components/status/index.vue';
let data = ref<any>();
let loading = ref(false);

View File

@ -119,8 +119,8 @@ let ssl = ref({
otherDomains: '',
provider: 'dnsAccount',
websiteId: 0,
acmeAccountId: 0,
dnsAccountId: 0,
acmeAccountId: undefined,
dnsAccountId: undefined,
});
let dnsResolve = ref<WebSite.DNSResolve[]>([]);
let hasResolve = ref(false);

View File

@ -18,7 +18,7 @@
</el-table-column>
<el-table-column :label="$t('website.key')">
<template #default="{ row }">
<el-link @click="openEdit(row)">{{ $t('website.check') }}</el-link>
<el-link type="primary" @click="openEdit(row)">{{ $t('website.check') }}</el-link>
</template>
</el-table-column>
<fu-table-operations

View File

@ -1,49 +1,60 @@
<template>
<LayoutContent :header="$t('website.ssl')">
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openSSL()">
{{ $t('commons.button.create') }}
</el-button>
<el-button type="primary" plain @click="openAcmeAccount()">
{{ $t('website.acmeAccountManage') }}
</el-button>
<el-button type="primary" plain @click="openDnsAccount()">
{{ $t('website.dnsAccountManage') }}
</el-button>
</template>
<el-table-column
:label="$t('website.domain')"
fix
show-overflow-tooltip
prop="primaryDomain"
></el-table-column>
<el-table-column
:label="$t('website.otherDomains')"
fix
show-overflow-tooltip
prop="domains"
></el-table-column>
<el-table-column :label="$t('website.brand')" fix show-overflow-tooltip prop="type"></el-table-column>
<el-table-column
prop="expireDate"
:label="$t('website.expireDate')"
:formatter="dateFromat"
show-overflow-tooltip
/>
<fu-table-operations
:ellipsis="1"
:buttons="buttons"
:label="$t('commons.table.operate')"
fixed="right"
fix
/>
</ComplexTable>
<DnsAccount ref="dnsAccountRef"></DnsAccount>
<AcmeAccount ref="acmeAccountRef"></AcmeAccount>
<Create ref="sslCreateRef" @close="search()"></Create>
<Renew ref="renewRef" @close="search()"></Renew>
</LayoutContent>
<el-card>
<LayoutContent :header="$t('website.ssl')">
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openSSL()">
{{ $t('commons.button.create') }}
</el-button>
<el-button type="primary" plain @click="openAcmeAccount()">
{{ $t('website.acmeAccountManage') }}
</el-button>
<el-button type="primary" plain @click="openDnsAccount()">
{{ $t('website.dnsAccountManage') }}
</el-button>
</template>
<el-table-column
:label="$t('website.domain')"
fix
show-overflow-tooltip
prop="primaryDomain"
></el-table-column>
<el-table-column
:label="$t('website.otherDomains')"
fix
show-overflow-tooltip
prop="domains"
></el-table-column>
<el-table-column :label="$t('ssl.provider')" fix show-overflow-tooltip prop="provider">
<template #default="{ row }">{{ getProvider(row.provider) }}</template>
</el-table-column>
<el-table-column
:label="$t('ssl.acmeAccount')"
fix
show-overflow-tooltip
prop="acmeAccount.email"
></el-table-column>
<el-table-column :label="$t('website.brand')" fix show-overflow-tooltip prop="type"></el-table-column>
<el-table-column
prop="expireDate"
:label="$t('website.expireDate')"
:formatter="dateFromat"
show-overflow-tooltip
/>
<fu-table-operations
:ellipsis="1"
:buttons="buttons"
:label="$t('commons.table.operate')"
fixed="right"
fix
/>
</ComplexTable>
<DnsAccount ref="dnsAccountRef"></DnsAccount>
<AcmeAccount ref="acmeAccountRef"></AcmeAccount>
<Create ref="sslCreateRef" @close="search()"></Create>
<Renew ref="renewRef" @close="search()"></Renew>
</LayoutContent>
</el-card>
</template>
<script lang="ts" setup>
@ -79,12 +90,6 @@ const buttons = [
openRenewSSL(row.id);
},
},
// {
// label: i18n.global.t('website.deploySSL'),
// click: function (row: WebSite.WebSite) {
// applySSL(row.id);
// },
// },
{
label: i18n.global.t('app.delete'),
click: function (row: WebSite.WebSite) {
@ -129,23 +134,18 @@ const deleteSSL = async (id: number) => {
search();
};
// const renewSSL = async (id: number) => {
// loading.value = true;
// await useDeleteData(RenewSSL, { SSLId: id }, 'website.renewHelper', false);
// loading.value = false;
// search();
// };
// const applySSL = async (sslId: number) => {
// loading.value = true;
// const apply = {
// websiteId: 0,
// SSLId: sslId,
// };
// await useDeleteData(ApplySSL, apply, 'website.deploySSLHelper', false);
// loading.value = false;
// search();
// };
const getProvider = (provider: string) => {
switch (provider) {
case 'dnsAccount':
return i18n.global.t('website.dnsAccount');
case 'dnsManual':
return i18n.global.t('website.dnsAccount');
case 'http':
return 'HTTP';
default:
return i18n.global.t('ssl.manualCreate');
}
};
onMounted(() => {
search();

View File

@ -10,7 +10,7 @@
:loading="loading"
>
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
<el-input v-model="form.primaryDomain"></el-input>
<el-input v-model="form.primaryDomain" disabled></el-input>
</el-form-item>
<el-form-item :label="$t('website.group')" prop="webSiteGroupID">
<el-select v-model="form.webSiteGroupId">

View File

@ -19,7 +19,7 @@
prop="primaryDomain"
>
<template #default="{ row }">
<el-link @click="openConfig(row.id)">{{ row.primaryDomain }}</el-link>
<el-link type="primary" @click="openConfig(row.id)">{{ row.primaryDomain }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.type')" fix prop="type">