2020-10-01 16:01:04 +08:00
Vue . component ( "ssl-config-box" , {
2020-12-03 21:07:08 +08:00
props : [ "v-ssl-policy" , "v-protocol" , "v-server-id" ] ,
2020-10-01 16:01:04 +08:00
created : function ( ) {
let that = this
setTimeout ( function ( ) {
that . sortableCipherSuites ( )
} , 100 )
} ,
data : function ( ) {
let policy = this . vSslPolicy
if ( policy == null ) {
policy = {
id : 0 ,
isOn : true ,
certRefs : [ ] ,
certs : [ ] ,
clientCARefs : [ ] ,
clientCACerts : [ ] ,
clientAuthType : 0 ,
minVersion : "TLS 1.1" ,
hsts : null ,
cipherSuitesIsOn : false ,
cipherSuites : [ ] ,
http2Enabled : true
}
} else {
if ( policy . certRefs == null ) {
policy . certRefs = [ ]
}
if ( policy . certs == null ) {
policy . certs = [ ]
}
if ( policy . clientCARefs == null ) {
policy . clientCARefs = [ ]
}
if ( policy . clientCACerts == null ) {
policy . clientCACerts = [ ]
}
if ( policy . cipherSuites == null ) {
policy . cipherSuites = [ ]
}
}
let hsts = policy . hsts
if ( hsts == null ) {
hsts = {
isOn : false ,
maxAge : 0 ,
includeSubDomains : false ,
preload : false ,
domains : [ ]
}
}
return {
policy : policy ,
// hsts
hsts : hsts ,
hstsOptionsVisible : false ,
hstsDomainAdding : false ,
addingHstsDomain : "" ,
hstsDomainEditingIndex : - 1 ,
// 相关数据
allVersions : window . SSL _ALL _VERSIONS ,
allCipherSuites : window . SSL _ALL _CIPHER _SUITES . $copy ( ) ,
modernCipherSuites : window . SSL _MODERN _CIPHER _SUITES ,
intermediateCipherSuites : window . SSL _INTERMEDIATE _CIPHER _SUITES ,
allClientAuthTypes : window . SSL _ALL _CLIENT _AUTH _TYPES ,
cipherSuitesVisible : false ,
// 高级选项
moreOptionsVisible : false
}
} ,
watch : {
hsts : {
deep : true ,
handler : function ( ) {
this . policy . hsts = this . hsts
}
}
} ,
methods : {
// 删除证书
removeCert : function ( index ) {
let that = this
teaweb . confirm ( "确定删除此证书吗?证书数据仍然保留,只是当前服务不再使用此证书。" , function ( ) {
that . policy . certRefs . $remove ( index )
that . policy . certs . $remove ( index )
} )
} ,
// 选择证书
selectCert : function ( ) {
let that = this
2020-11-24 17:36:42 +08:00
teaweb . popup ( "/servers/certs/selectPopup" , {
2020-10-01 16:01:04 +08:00
width : "50em" ,
height : "30em" ,
callback : function ( resp ) {
that . policy . certRefs . push ( resp . data . certRef )
that . policy . certs . push ( resp . data . cert )
}
} )
} ,
// 上传证书
uploadCert : function ( ) {
let that = this
2020-11-24 17:36:42 +08:00
teaweb . popup ( "/servers/certs/uploadPopup" , {
2020-10-01 16:01:04 +08:00
height : "28em" ,
callback : function ( resp ) {
teaweb . success ( "上传成功" , function ( ) {
that . policy . certRefs . push ( resp . data . certRef )
that . policy . certs . push ( resp . data . cert )
} )
}
} )
} ,
2020-12-03 21:07:08 +08:00
// 申请证书
requestCert : function ( ) {
// 已经在证书中的域名
let excludeServerNames = [ ]
if ( this . policy != null && this . policy . certs . length > 0 ) {
this . policy . certs . forEach ( function ( cert ) {
excludeServerNames . $pushAll ( cert . dnsNames )
} )
}
let that = this
teaweb . popup ( "/servers/server/settings/https/requestCertPopup?serverId=" + this . vServerId + "&excludeServerNames=" + excludeServerNames . join ( "," ) , {
callback : function ( ) {
that . policy . certRefs . push ( resp . data . certRef )
that . policy . certs . push ( resp . data . cert )
}
} )
} ,
2020-10-01 16:01:04 +08:00
// 更多选项
changeOptionsVisible : function ( ) {
this . moreOptionsVisible = ! this . moreOptionsVisible
} ,
// 格式化时间
formatTime : function ( timestamp ) {
return new Date ( timestamp * 1000 ) . format ( "Y-m-d" )
} ,
// 格式化加密套件
formatCipherSuite : function ( cipherSuite ) {
return cipherSuite . replace ( /(AES|3DES)/ , "<var style=\"font-weight: bold\">$1</var>" )
} ,
// 添加单个套件
addCipherSuite : function ( cipherSuite ) {
if ( ! this . policy . cipherSuites . $contains ( cipherSuite ) ) {
this . policy . cipherSuites . push ( cipherSuite )
}
this . allCipherSuites . $removeValue ( cipherSuite )
} ,
// 删除单个套件
removeCipherSuite : function ( cipherSuite ) {
let that = this
teaweb . confirm ( "确定要删除此套件吗?" , function ( ) {
that . policy . cipherSuites . $removeValue ( cipherSuite )
that . allCipherSuites = window . SSL _ALL _CIPHER _SUITES . $findAll ( function ( k , v ) {
return ! that . policy . cipherSuites . $contains ( v )
} )
} )
} ,
// 清除所选套件
clearCipherSuites : function ( ) {
let that = this
teaweb . confirm ( "确定要清除所有已选套件吗?" , function ( ) {
that . policy . cipherSuites = [ ]
that . allCipherSuites = window . SSL _ALL _CIPHER _SUITES . $copy ( )
} )
} ,
// 批量添加套件
addBatchCipherSuites : function ( suites ) {
var that = this
teaweb . confirm ( "确定要批量添加套件?" , function ( ) {
suites . $each ( function ( k , v ) {
if ( that . policy . cipherSuites . $contains ( v ) ) {
return
}
that . policy . cipherSuites . push ( v )
} )
} )
} ,
/ * *
* 套件拖动排序
* /
sortableCipherSuites : function ( ) {
var box = document . querySelector ( ".cipher-suites-box" )
Sortable . create ( box , {
draggable : ".label" ,
handle : ".icon.handle" ,
onStart : function ( ) {
} ,
onUpdate : function ( event ) {
}
} )
} ,
// 显示所有套件
showAllCipherSuites : function ( ) {
this . cipherSuitesVisible = ! this . cipherSuitesVisible
} ,
// 显示HSTS更多选项
showMoreHSTS : function ( ) {
this . hstsOptionsVisible = ! this . hstsOptionsVisible ;
if ( this . hstsOptionsVisible ) {
this . changeHSTSMaxAge ( )
}
} ,
// 监控HSTS有效期修改
changeHSTSMaxAge : function ( ) {
var v = this . hsts . maxAge
if ( isNaN ( v ) ) {
this . hsts . days = "-"
return
}
this . hsts . days = parseInt ( v / 86400 )
if ( isNaN ( this . hsts . days ) ) {
this . hsts . days = "-"
} else if ( this . hsts . days < 0 ) {
this . hsts . days = "-"
}
} ,
// 设置HSTS有效期
setHSTSMaxAge : function ( maxAge ) {
this . hsts . maxAge = maxAge
this . changeHSTSMaxAge ( )
} ,
// 添加HSTS域名
addHstsDomain : function ( ) {
this . hstsDomainAdding = true
this . hstsDomainEditingIndex = - 1
let that = this
setTimeout ( function ( ) {
that . $refs . addingHstsDomain . focus ( )
} , 100 )
} ,
// 修改HSTS域名
editHstsDomain : function ( index ) {
this . hstsDomainEditingIndex = index
this . addingHstsDomain = this . hsts . domains [ index ]
this . hstsDomainAdding = true
let that = this
setTimeout ( function ( ) {
that . $refs . addingHstsDomain . focus ( )
} , 100 )
} ,
// 确认HSTS域名添加
confirmAddHstsDomain : function ( ) {
this . addingHstsDomain = this . addingHstsDomain . trim ( )
if ( this . addingHstsDomain . length == 0 ) {
return ;
}
if ( this . hstsDomainEditingIndex > - 1 ) {
this . hsts . domains [ this . hstsDomainEditingIndex ] = this . addingHstsDomain
} else {
this . hsts . domains . push ( this . addingHstsDomain )
}
this . cancelHstsDomainAdding ( )
} ,
// 取消HSTS域名添加
cancelHstsDomainAdding : function ( ) {
this . hstsDomainAdding = false
this . addingHstsDomain = ""
this . hstsDomainEditingIndex = - 1
} ,
// 删除HSTS域名
removeHstsDomain : function ( index ) {
this . cancelHstsDomainAdding ( )
this . hsts . domains . $remove ( index )
} ,
// 选择客户端CA证书
selectClientCACert : function ( ) {
let that = this
2020-11-24 17:36:42 +08:00
teaweb . popup ( "/servers/certs/selectPopup?isCA=1" , {
2020-10-01 16:01:04 +08:00
width : "50em" ,
height : "30em" ,
callback : function ( resp ) {
that . policy . clientCARefs . push ( resp . data . certRef )
that . policy . clientCACerts . push ( resp . data . cert )
}
} )
} ,
// 上传CA证书
uploadClientCACert : function ( ) {
let that = this
2020-11-24 17:36:42 +08:00
teaweb . popup ( "/servers/certs/uploadPopup?isCA=1" , {
2020-10-01 16:01:04 +08:00
height : "28em" ,
callback : function ( resp ) {
teaweb . success ( "上传成功" , function ( ) {
that . policy . clientCARefs . push ( resp . data . certRef )
that . policy . clientCACerts . push ( resp . data . cert )
} )
}
} )
} ,
// 删除客户端CA证书
removeClientCACert : function ( index ) {
let that = this
teaweb . confirm ( "确定删除此证书吗?证书数据仍然保留,只是当前服务不再使用此证书。" , function ( ) {
that . policy . clientCARefs . $remove ( index )
that . policy . clientCACerts . $remove ( index )
} )
}
} ,
template : ` <div>
< h4 > SSL / TLS相关配置 < / h 4 >
< input type = "hidden" name = "sslPolicyJSON" : value = "JSON.stringify(policy)" / >
< table class = "ui table definition selectable" >
< tbody >
2020-10-01 16:51:32 +08:00
< tr v - show = "vProtocol == 'https'" >
2020-11-30 22:27:55 +08:00
< td class = "title" > 启用HTTP / 2 < / t d >
2020-10-01 16:01:04 +08:00
< td >
< div class = "ui checkbox" >
< input type = "checkbox" value = "1" v - model = "policy.http2Enabled" / >
< label > < / l a b e l >
< / d i v >
< / t d >
< / t r >
< tr >
2020-10-01 16:51:32 +08:00
< td class = "title" > 选择证书 < / t d >
2020-10-01 16:01:04 +08:00
< td >
< div v - if = "policy.certs != null && policy.certs.length > 0" >
< div class = "ui label small" v - for = "(cert, index) in policy.certs" >
{ { cert . name } } / { { cert . dnsNames } } / 有效至 { { formatTime ( cert . timeEndAt ) } } & nbsp ; < a href = "" title = "删除" @ click . prevent = "removeCert()" > < i class = "icon remove" > < / i > < / a >
< / d i v >
< div class = "ui divider" > < / d i v >
< / d i v >
< div v - else >
< span class = "red" > 选择或上传证书后 < span v - if = "vProtocol == 'https'" > HTTPS < / s p a n > < s p a n v - i f = " v P r o t o c o l = = ' t l s ' " > T L S < / s p a n > 服 务 才 能 生 效 。 < / s p a n >
< div class = "ui divider" > < / d i v >
< / d i v >
< button class = "ui button tiny" type = "button" @ click . prevent = "selectCert()" > 选择已有证书 < / b u t t o n > & n b s p ;
2020-12-03 21:07:08 +08:00
< button class = "ui button tiny" type = "button" @ click . prevent = "uploadCert()" > 上传新证书 < / b u t t o n > & n b s p ;
< button class = "ui button tiny" type = "button" @ click . prevent = "requestCert()" v - if = "vServerId != null && vServerId > 0" > 申请免费证书 < / b u t t o n >
2020-10-01 16:01:04 +08:00
< / t d >
< / t r >
< tr >
< td > TLS最低版本 < / t d >
< td >
< select v - model = "policy.minVersion" class = "ui dropdown auto-width" >
< option v - for = "version in allVersions" : value = "version" > { { version } } < / o p t i o n >
< / s e l e c t >
< / t d >
< / t r >
< / t b o d y >
< more - options - tbody @ change = "changeOptionsVisible" > < / m o r e - o p t i o n s - t b o d y >
< tbody v - show = "moreOptionsVisible" >
<!-- 加密套件 -- >
< tr >
< td > 加密算法套件 < em > ( CipherSuites ) < / e m > < / t d >
< td >
< div class = "ui checkbox" >
< input type = "checkbox" value = "1" v - model = "policy.cipherSuitesIsOn" / >
< label > 是否要自定义 < / l a b e l >
< / d i v >
< div v - show = "policy.cipherSuitesIsOn" >
< div class = "ui divider" > < / d i v >
< div class = "cipher-suites-box" >
已添加套件 ( { { policy . cipherSuites . length } } ) :
2020-11-21 15:53:04 +08:00
< div v - for = "cipherSuite in policy.cipherSuites" class = "ui label tiny basic" style = "margin-bottom: 0.5em" >
2020-10-01 16:01:04 +08:00
< input type = "hidden" name = "cipherSuites" : value = "cipherSuite" / >
< span v - html = "formatCipherSuite(cipherSuite)" > < /span> <a href="" title="删除套件" @click.prevent="removeCipherSuite(cipherSuite)"><i class="icon remove"></i > < / a >
< a href = "" title = "拖动改变顺序" > < i class = "icon bars handle" > < / i > < / a >
< / d i v >
< / d i v >
< div >
< div class = "ui divider" > < / d i v >
< span v - if = "policy.cipherSuites.length > 0" > < a href = "" @ click . prevent = "clearCipherSuites()" > [ 清除所有已选套件 ] < / a > & n b s p ; < / s p a n >
< a href = "" @ click . prevent = "addBatchCipherSuites(modernCipherSuites)" > [ 添加推荐套件 ] < / a > & n b s p ;
< a href = "" @ click . prevent = "addBatchCipherSuites(intermediateCipherSuites)" > [ 添加兼容套件 ] < / a >
< div class = "ui divider" > < / d i v >
< / d i v >
< div class = "cipher-all-suites-box" >
< a href = "" @ click . prevent = "showAllCipherSuites()" > < span v - if = "policy.cipherSuites.length == 0" > 所有 < /span>可选套件({{allCipherSuites.length}}) <i class="icon angle" :class="{down:!cipherSuitesVisible, up:cipherSuitesVisible}"></i > < / a >
< a href = "" v - if = "cipherSuitesVisible" v - for = "cipherSuite in allCipherSuites" class = "ui label tiny" title = "点击添加到自定义套件中" @ click . prevent = "addCipherSuite(cipherSuite)" v - html = "formatCipherSuite(cipherSuite)" style = "margin-bottom:0.5em" > < / a >
< / d i v >
< p class = "comment" v - if = "cipherSuitesVisible" > 点击可选套件添加 。 < / p >
< / d i v >
< / t d >
< / t r >
<!-- HSTS -- >
< tr v - show = "vProtocol == 'https'" >
< td : class = "{'color-border':hsts.isOn}" > 是否开启HSTS < / t d >
< td >
< div class = "ui checkbox" >
< input type = "checkbox" name = "hstsOn" v - model = "hsts.isOn" value = "1" / >
< label > < / l a b e l >
< / d i v >
< p class = "comment" >
开启后 , 会自动在响应Header中加入
< span class = "ui label small" > Strict - Transport - Security :
< var v - if = "!hsts.isOn" > ... < / v a r >
< var v - if = "hsts.isOn" > < span > max - age = < / s p a n > { { h s t s . m a x A g e } } < / v a r >
< var v - if = "hsts.isOn && hsts.includeSubDomains" > ; includeSubDomains < / v a r >
< var v - if = "hsts.isOn && hsts.preload" > ; preload < / v a r >
< / s p a n >
< span v - if = "hsts.isOn" >
< a href = "" @ click . prevent = "showMoreHSTS()" > 修改 < i class = "icon angle" : class = "{down:!hstsOptionsVisible, up:hstsOptionsVisible}" > < / i > < / a >
< / s p a n >
< / p >
< / t d >
< / t r >
< tr v - show = "hsts.isOn && hstsOptionsVisible" >
< td class = "color-border" > HSTS包含子域名 < em > ( includeSubDomains ) < / e m > < / t d >
< td >
< div class = "ui checkbox" >
< input type = "checkbox" name = "hstsIncludeSubDomains" value = "1" v - model = "hsts.includeSubDomains" / >
< label > < / l a b e l >
< / d i v >
< / t d >
< / t r >
< tr v - show = "hsts.isOn && hstsOptionsVisible" >
< td class = "color-border" > HSTS预加载 < em > ( preload ) < / e m > < / t d >
< td >
< div class = "ui checkbox" >
< input type = "checkbox" name = "hstsPreload" value = "1" v - model = "hsts.preload" / >
< label > < / l a b e l >
< / d i v >
< / t d >
< / t r >
< tr v - show = "hsts.isOn && hstsOptionsVisible" >
< td class = "color-border" > HSTS生效的域名 < / t d >
< td colspan = "2" >
< div class = "names-box" >
2020-11-21 15:53:04 +08:00
< span class = "ui label tiny basic" v - for = "(domain, arrayIndex) in hsts.domains" : class = "{blue:hstsDomainEditingIndex == arrayIndex}" > { { domain } }
2020-10-01 16:01:04 +08:00
< input type = "hidden" name = "hstsDomains" : value = "domain" / > & nbsp ;
< a href = "" @ click . prevent = "editHstsDomain(arrayIndex)" title = "修改" > < i class = "icon pencil" > < / i > < / a >
< a href = "" @ click . prevent = "removeHstsDomain(arrayIndex)" title = "删除" > < i class = "icon remove" > < / i > < / a >
< / s p a n >
< / d i v >
< div class = "ui fields inline" v - if = "hstsDomainAdding" style = "margin-top:0.8em" >
< div class = "ui field" >
< input type = "text" name = "addingHstsDomain" ref = "addingHstsDomain" style = "width:16em" maxlength = "100" placeholder = "域名, 比如example.com" @ keyup . enter = "confirmAddHstsDomain()" @ keypress . enter . prevent = "1" v - model = "addingHstsDomain" / >
< / d i v >
< div class = "ui field" >
< button class = "ui button tiny" type = "button" @ click = "confirmAddHstsDomain()" > 确定 < / b u t t o n >
& nbsp ; < a href = "" @ click . prevent = "cancelHstsDomainAdding()" > 取消 < / a >
< / d i v >
< / d i v >
< div class = "ui field" style = "margin-top: 1em" >
< button class = "ui button tiny" type = "button" @ click = "addHstsDomain()" > + < / b u t t o n >
< / d i v >
< p class = "comment" > 如果没有设置域名的话 , 则默认支持所有的域名 。 < / p >
< / t d >
< / t r >
<!-- 客户端认证 -- >
< tr >
< td > 客户端认证方式 < / t d >
< td >
< select name = "clientAuthType" v - model = "policy.clientAuthType" class = "ui dropdown auto-width" >
< option v - for = "authType in allClientAuthTypes" : value = "authType.type" > { { authType . name } } < / o p t i o n >
< / s e l e c t >
< / t d >
< / t r >
< tr >
< td > 客户端认证CA证书 < / t d >
< td >
< div v - if = "policy.clientCACerts != null && policy.clientCACerts.length > 0" >
< div class = "ui label small" v - for = "(cert, index) in policy.clientCACerts" >
{ { cert . name } } / { { cert . dnsNames } } / 有效至 { { formatTime ( cert . timeEndAt ) } } & nbsp ; < a href = "" title = "删除" @ click . prevent = "removeClientCACert()" > < i class = "icon remove" > < / i > < / a >
< / d i v >
< div class = "ui divider" > < / d i v >
< / d i v >
< button class = "ui button tiny" type = "button" @ click . prevent = "selectClientCACert()" > 选择已有证书 < / b u t t o n > & n b s p ;
< button class = "ui button tiny" type = "button" @ click . prevent = "uploadClientCACert()" > 上传新证书 < / b u t t o n >
< p class = "comment" > 用来校验客户端证书以增强安全性 , 通常不需要设置 。 < / p >
< / t d >
< / t r >
< / t b o d y >
< / t a b l e >
< div class = "ui margin" > < / d i v >
< / d i v > `
} )