327 lines
7.7 KiB
Go
327 lines
7.7 KiB
Go
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||
|
||
package serverconfigs
|
||
|
||
import (
|
||
"regexp"
|
||
"strings"
|
||
)
|
||
|
||
// HTTPPageEncryptionConfig 页面动态加密配置
|
||
type HTTPPageEncryptionConfig struct {
|
||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用(用于序列化)
|
||
|
||
// 加密范围
|
||
HTML *HTTPHTMLEncryptionConfig `yaml:"html" json:"html"`
|
||
Javascript *HTTPJavascriptEncryptionConfig `yaml:"javascript" json:"javascript"`
|
||
|
||
// 密钥策略
|
||
KeyPolicy *EncryptionKeyPolicy `yaml:"keyPolicy" json:"keyPolicy"`
|
||
|
||
// 白名单
|
||
ExcludeURLs []string `yaml:"excludeURLs" json:"excludeURLs"`
|
||
|
||
// 缓存配置
|
||
Cache *EncryptionCacheConfig `yaml:"cache" json:"cache"`
|
||
|
||
// 内部状态(初始化后计算得出)
|
||
enabled bool
|
||
|
||
excludeURLPatterns []*regexp.Regexp
|
||
}
|
||
|
||
// NewHTTPPageEncryptionConfig 创建新配置
|
||
func NewHTTPPageEncryptionConfig() *HTTPPageEncryptionConfig {
|
||
return &HTTPPageEncryptionConfig{
|
||
IsOn: false,
|
||
HTML: NewHTTPHTMLEncryptionConfig(),
|
||
Javascript: NewHTTPJavascriptEncryptionConfig(),
|
||
KeyPolicy: NewEncryptionKeyPolicy(),
|
||
ExcludeURLs: []string{},
|
||
Cache: NewEncryptionCacheConfig(),
|
||
}
|
||
}
|
||
|
||
// Init 初始化
|
||
func (this *HTTPPageEncryptionConfig) Init() error {
|
||
// 计算是否启用
|
||
this.enabled = this.IsOn && ((this.HTML != nil && this.HTML.IsOn) ||
|
||
(this.Javascript != nil && this.Javascript.IsOn))
|
||
|
||
// 初始化 HTML 配置
|
||
if this.HTML != nil {
|
||
err := this.HTML.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// 如果 HTML 启用,则整体启用(需总开关开启)
|
||
if this.IsOn && this.HTML.IsOn {
|
||
this.enabled = true
|
||
}
|
||
}
|
||
|
||
// 初始化 JavaScript 配置
|
||
if this.Javascript != nil {
|
||
err := this.Javascript.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
// 如果 JavaScript 启用,则整体启用(需总开关开启)
|
||
if this.IsOn && this.Javascript.IsOn {
|
||
this.enabled = true
|
||
}
|
||
}
|
||
|
||
// 初始化密钥策略
|
||
if this.KeyPolicy != nil {
|
||
err := this.KeyPolicy.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
// 初始化缓存配置
|
||
if this.Cache != nil {
|
||
err := this.Cache.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
// 编译排除 URL 正则表达式
|
||
this.excludeURLPatterns = []*regexp.Regexp{}
|
||
for _, pattern := range this.ExcludeURLs {
|
||
if len(pattern) > 0 {
|
||
reg, err := regexp.Compile(pattern)
|
||
if err == nil {
|
||
this.excludeURLPatterns = append(this.excludeURLPatterns, reg)
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// IsEnabled 检查是否启用(初始化后使用此方法)
|
||
func (this *HTTPPageEncryptionConfig) IsEnabled() bool {
|
||
return this.enabled
|
||
}
|
||
|
||
// MatchExcludeURL 检查 URL 是否在白名单中
|
||
func (this *HTTPPageEncryptionConfig) MatchExcludeURL(url string) bool {
|
||
if len(this.excludeURLPatterns) == 0 {
|
||
return false
|
||
}
|
||
|
||
for _, reg := range this.excludeURLPatterns {
|
||
if reg.MatchString(url) {
|
||
return true
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// HTTPHTMLEncryptionConfig HTML 加密配置
|
||
type HTTPHTMLEncryptionConfig struct {
|
||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||
|
||
// URL 匹配规则
|
||
URLPatterns []string `yaml:"urlPatterns" json:"urlPatterns"`
|
||
|
||
// 加密策略
|
||
EncryptInlineScripts bool `yaml:"encryptInlineScripts" json:"encryptInlineScripts"` // 内联脚本
|
||
EncryptExternalScripts bool `yaml:"encryptExternalScripts" json:"encryptExternalScripts"` // 外部脚本
|
||
|
||
urlPatternRegexps []*regexp.Regexp
|
||
}
|
||
|
||
// NewHTTPHTMLEncryptionConfig 创建新配置
|
||
func NewHTTPHTMLEncryptionConfig() *HTTPHTMLEncryptionConfig {
|
||
return &HTTPHTMLEncryptionConfig{
|
||
IsOn: false,
|
||
URLPatterns: []string{},
|
||
EncryptInlineScripts: true,
|
||
EncryptExternalScripts: true,
|
||
}
|
||
}
|
||
|
||
// Init 初始化
|
||
func (this *HTTPHTMLEncryptionConfig) Init() error {
|
||
// 编译 URL 匹配规则
|
||
this.urlPatternRegexps = []*regexp.Regexp{}
|
||
for _, pattern := range this.URLPatterns {
|
||
if len(pattern) > 0 {
|
||
reg, err := regexp.Compile(pattern)
|
||
if err == nil {
|
||
this.urlPatternRegexps = append(this.urlPatternRegexps, reg)
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// MatchURL 检查 URL 是否匹配
|
||
func (this *HTTPHTMLEncryptionConfig) MatchURL(url string) bool {
|
||
if len(this.urlPatternRegexps) == 0 {
|
||
return true // 如果没有配置规则,默认匹配所有
|
||
}
|
||
|
||
for _, reg := range this.urlPatternRegexps {
|
||
if reg.MatchString(url) {
|
||
return true
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// HTTPJavascriptEncryptionConfig JavaScript 加密配置
|
||
type HTTPJavascriptEncryptionConfig struct {
|
||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||
|
||
// URL 匹配规则
|
||
URLPatterns []string `yaml:"urlPatterns" json:"urlPatterns"`
|
||
|
||
urlPatternRegexps []*regexp.Regexp
|
||
}
|
||
|
||
// NewHTTPJavascriptEncryptionConfig 创建新配置
|
||
func NewHTTPJavascriptEncryptionConfig() *HTTPJavascriptEncryptionConfig {
|
||
return &HTTPJavascriptEncryptionConfig{
|
||
IsOn: false,
|
||
URLPatterns: []string{},
|
||
}
|
||
}
|
||
|
||
// Init 初始化
|
||
func (this *HTTPJavascriptEncryptionConfig) Init() error {
|
||
// 编译 URL 匹配规则
|
||
this.urlPatternRegexps = []*regexp.Regexp{}
|
||
for _, pattern := range this.URLPatterns {
|
||
if len(pattern) > 0 {
|
||
reg, err := regexp.Compile(pattern)
|
||
if err == nil {
|
||
this.urlPatternRegexps = append(this.urlPatternRegexps, reg)
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// MatchURL 检查 URL 是否匹配
|
||
func (this *HTTPJavascriptEncryptionConfig) MatchURL(url string) bool {
|
||
if len(this.urlPatternRegexps) == 0 {
|
||
return true // 如果没有配置规则,默认匹配所有
|
||
}
|
||
|
||
for _, reg := range this.urlPatternRegexps {
|
||
if reg.MatchString(url) {
|
||
return true
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
// EncryptionKeyPolicy 加密密钥策略
|
||
type EncryptionKeyPolicy struct {
|
||
// 时间分片(秒)
|
||
TimeBucket int64 `yaml:"timeBucket" json:"timeBucket"` // 默认 60-120 秒
|
||
|
||
// IP 归一化(CIDR 前缀长度)
|
||
IPCIDR int `yaml:"ipCIDR" json:"ipCIDR"` // 默认 24
|
||
|
||
// UA 简化策略
|
||
UASimplify bool `yaml:"uaSimplify" json:"uaSimplify"` // 是否简化 UA
|
||
|
||
// 服务器端密钥(用于 HMAC)
|
||
ServerSecret string `yaml:"serverSecret" json:"serverSecret"`
|
||
}
|
||
|
||
// NewEncryptionKeyPolicy 创建新配置
|
||
func NewEncryptionKeyPolicy() *EncryptionKeyPolicy {
|
||
return &EncryptionKeyPolicy{
|
||
TimeBucket: 60, // 默认 60 秒
|
||
IPCIDR: 24, // 默认 /24
|
||
UASimplify: true,
|
||
ServerSecret: "WAFEncryptionSecret@123", // 默认密钥,生产环境应修改
|
||
}
|
||
}
|
||
|
||
// Init 初始化
|
||
func (this *EncryptionKeyPolicy) Init() error {
|
||
if this.TimeBucket <= 0 {
|
||
this.TimeBucket = 60
|
||
}
|
||
if this.IPCIDR <= 0 {
|
||
this.IPCIDR = 24
|
||
}
|
||
if len(this.ServerSecret) == 0 {
|
||
this.ServerSecret = "WAFEncryptionSecret@123"
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// EncryptionCacheConfig 加密缓存配置
|
||
type EncryptionCacheConfig struct {
|
||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||
TTL int64 `yaml:"ttl" json:"ttl"` // 缓存 TTL(秒),默认 60
|
||
MaxSize int `yaml:"maxSize" json:"maxSize"` // 最大缓存条目数,默认 1000
|
||
}
|
||
|
||
// NewEncryptionCacheConfig 创建新配置
|
||
func NewEncryptionCacheConfig() *EncryptionCacheConfig {
|
||
return &EncryptionCacheConfig{
|
||
IsOn: true,
|
||
TTL: 60,
|
||
MaxSize: 1000,
|
||
}
|
||
}
|
||
|
||
// Init 初始化
|
||
func (this *EncryptionCacheConfig) Init() error {
|
||
if this.TTL <= 0 {
|
||
this.TTL = 60
|
||
}
|
||
if this.MaxSize <= 0 {
|
||
this.MaxSize = 1000
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// SimplifyUserAgent 简化 User-Agent
|
||
func SimplifyUserAgent(ua string) string {
|
||
if len(ua) == 0 {
|
||
return ""
|
||
}
|
||
|
||
// 提取主要信息:浏览器类型和版本
|
||
ua = strings.ToLower(ua)
|
||
|
||
// Chrome
|
||
if strings.Contains(ua, "chrome") {
|
||
return "chrome"
|
||
}
|
||
// Safari
|
||
if strings.Contains(ua, "safari") && !strings.Contains(ua, "chrome") {
|
||
return "safari"
|
||
}
|
||
// Firefox
|
||
if strings.Contains(ua, "firefox") {
|
||
return "firefox"
|
||
}
|
||
// Edge
|
||
if strings.Contains(ua, "edge") {
|
||
return "edge"
|
||
}
|
||
// Opera
|
||
if strings.Contains(ua, "opera") {
|
||
return "opera"
|
||
}
|
||
|
||
return "other"
|
||
}
|