152 lines
3.4 KiB
Go
152 lines
3.4 KiB
Go
package api
|
||
|
||
import (
|
||
"unsafe"
|
||
|
||
"apigo.cc/go/cast"
|
||
"apigo.cc/go/safe"
|
||
)
|
||
|
||
// Action 是所有接口的基础标识接口
|
||
type Action interface {
|
||
ActionName() string // 例如: "tencent.sms.send"
|
||
}
|
||
|
||
// SignerAction 定义需要签名的动作
|
||
type SignerAction interface {
|
||
SignerName() string // 例如: "tc3"
|
||
}
|
||
|
||
// ConfigurableAction 定义可以提供默认硬编码配置的动作
|
||
type ConfigurableAction interface {
|
||
Config() map[string]any
|
||
}
|
||
|
||
// URLAction 定义显式指定 URL 的动作
|
||
type URLAction interface {
|
||
GetURL() string
|
||
}
|
||
|
||
// MethodAction 定义显式指定方法的动作
|
||
type MethodAction interface {
|
||
GetMethod() string // 例如: "GET"
|
||
}
|
||
|
||
// ValidatableAction 定义支持自我校验的动作
|
||
type ValidatableAction interface {
|
||
Validate() error
|
||
}
|
||
|
||
// HttpRequest 内部使用的请求描述结构,供 Signer 使用
|
||
type HttpRequest struct {
|
||
Url string
|
||
Method string
|
||
headers map[string]string
|
||
Payload any
|
||
wipeableBuffers [][]byte // 追踪需要安全擦除的敏感缓冲区
|
||
}
|
||
|
||
// GetHeader 获取指定 Header 的值
|
||
func (r *HttpRequest) GetHeader(key string) string {
|
||
if r == nil || r.headers == nil {
|
||
return ""
|
||
}
|
||
return r.headers[key]
|
||
}
|
||
|
||
// Close 物理覆盖并清除所有关联的敏感缓冲区,确保内存中不再留存明文
|
||
func (r *HttpRequest) Close() {
|
||
if r == nil {
|
||
return
|
||
}
|
||
// 擦除缓冲区
|
||
for _, buffer := range r.wipeableBuffers {
|
||
safe.ZeroMemory(buffer)
|
||
}
|
||
r.wipeableBuffers = nil
|
||
}
|
||
|
||
// SetHeader 提供无感知的安全 Header 设置功能。支持传入多个参数进行自动拼接。
|
||
// 如果参数中包含 *safe.SafeBuf, *safe.SecretPlaintext 或 []byte (标记为敏感),
|
||
// 整个生成的 Header 缓冲区都将被注册用于后置物理擦除。
|
||
// 安全的拼接与转换(如 safe.Concat, safe.Base64)建议使用 safe 包提供的返回 *safe.SafeBuf 的方法。
|
||
func (r *HttpRequest) SetHeader(key string, values ...any) {
|
||
if len(values) == 0 {
|
||
return
|
||
}
|
||
|
||
if r.headers == nil {
|
||
r.headers = make(map[string]string)
|
||
}
|
||
|
||
// 1. 计算总长度并识别是否有敏感数据
|
||
totalLen := 0
|
||
isSensitive := false
|
||
for _, v := range values {
|
||
switch t := v.(type) {
|
||
case string:
|
||
totalLen += len(t)
|
||
case []byte:
|
||
totalLen += len(t)
|
||
isSensitive = true
|
||
case *safe.SafeBuf:
|
||
if t == nil {
|
||
continue
|
||
}
|
||
p := t.Open()
|
||
totalLen += len(p.Data)
|
||
p.Close()
|
||
isSensitive = true
|
||
case *safe.SecretPlaintext:
|
||
if t == nil {
|
||
continue
|
||
}
|
||
totalLen += len(t.Data)
|
||
isSensitive = true
|
||
default:
|
||
s := cast.String(v)
|
||
totalLen += len(s)
|
||
}
|
||
}
|
||
|
||
// 2. 分配单一缓冲区进行拼接
|
||
buf := make([]byte, totalLen)
|
||
pos := 0
|
||
for _, v := range values {
|
||
switch t := v.(type) {
|
||
case string:
|
||
pos += copy(buf[pos:], t)
|
||
case []byte:
|
||
pos += copy(buf[pos:], t)
|
||
case *safe.SafeBuf:
|
||
if t == nil {
|
||
continue
|
||
}
|
||
p := t.Open()
|
||
pos += copy(buf[pos:], p.Data)
|
||
p.Close()
|
||
case *safe.SecretPlaintext:
|
||
if t == nil {
|
||
continue
|
||
}
|
||
pos += copy(buf[pos:], t.Data)
|
||
default:
|
||
pos += copy(buf[pos:], cast.String(v))
|
||
}
|
||
}
|
||
|
||
// 3. 映射到 headers 并注册清理
|
||
r.headers[key] = unsafe.String(&buf[0], len(buf))
|
||
if isSensitive {
|
||
r.wipeableBuffers = append(r.wipeableBuffers, buf)
|
||
}
|
||
}
|
||
|
||
// Result 定义 API 调用的标准返回结果
|
||
type Result struct {
|
||
StatusCode int
|
||
Status string
|
||
Headers map[string]string
|
||
Data any
|
||
}
|