mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 22:06:38 +08:00
docs: add package and exported symbol comments for revive lint compliance
This commit is contained in:
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package auth_source 提供认证源管理功能
|
||||
package auth_source
|
||||
|
||||
import (
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AuthSourceRequest 创建或更新认证源的请求参数
|
||||
type AuthSourceRequest struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
@@ -39,6 +41,7 @@ type AuthSourceRequest struct {
|
||||
IconURL string `json:"icon_url"`
|
||||
}
|
||||
|
||||
// ToggleAuthSourceRequest 切换认证源启用状态的请求参数
|
||||
type ToggleAuthSourceRequest struct {
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package admin 提供管理后台功能
|
||||
package admin
|
||||
|
||||
// 管理后台错误消息常量
|
||||
const (
|
||||
AdminRequired = "未经授权访问"
|
||||
InvalidAuthSourceID = "认证源 ID 无效"
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// LoginAdminRequired 返回管理员权限校验中间件
|
||||
func LoginAdminRequired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// init trace
|
||||
|
||||
@@ -15,8 +15,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package system_config 提供系统配置管理功能
|
||||
package system_config
|
||||
|
||||
// 系统配置错误消息常量
|
||||
const (
|
||||
SystemConfigNotFound = "系统配置不存在"
|
||||
ConfigKeyRequired = "配置键不能为空"
|
||||
|
||||
@@ -15,8 +15,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package task 提供任务管理接口
|
||||
package task
|
||||
|
||||
// 任务管理相关错误消息
|
||||
const (
|
||||
InvalidTaskType = "无效的任务类型"
|
||||
InvalidTimeRange = "无效的时间范围"
|
||||
|
||||
@@ -14,8 +14,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package template 提供模板管理功能
|
||||
package template
|
||||
|
||||
// 模板管理相关错误消息
|
||||
const (
|
||||
TemplateNotFound = "模板不存在"
|
||||
TemplateKeyRequired = "模板标识符不能为空"
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package user 提供用户管理功能
|
||||
package user
|
||||
|
||||
const (
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package cap 提供人机验证中间件
|
||||
package cap
|
||||
|
||||
const (
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package health 提供健康检查端点
|
||||
package health
|
||||
|
||||
import (
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package oauth 提供 OAuth/OIDC 认证与会话管理
|
||||
package oauth
|
||||
|
||||
import (
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// LogForAudit 将登录鉴权审计日志写入 Logger
|
||||
func LogForAudit(ctx context.Context, user *model.User, c *gin.Context) {
|
||||
auditLog := loginRequiredAuditLog{
|
||||
UserID: user.ID,
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Session 用户信息字段 Key
|
||||
const (
|
||||
UserNameKey = "username"
|
||||
UserIDKey = "user_id"
|
||||
@@ -32,11 +33,13 @@ const (
|
||||
PendingOAuthEmailKey = "pending_oauth_email"
|
||||
)
|
||||
|
||||
// OAuth State 缓存 Key 格式与过期时间
|
||||
const (
|
||||
OAuthStateCacheKeyFormat = "oauth:state:%s"
|
||||
OAuthStateCacheKeyExpiration = 10 * time.Minute
|
||||
)
|
||||
|
||||
// OAuth 授权用途常量
|
||||
const (
|
||||
OAuthPurposeLogin = "login"
|
||||
OAuthPurposeBind = "bind"
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
|
||||
package oauth
|
||||
|
||||
// OAuth 认证相关错误消息
|
||||
const (
|
||||
InvalidState = "非法登录请求"
|
||||
IDTokenVerifyFailed = "ID Token 验证失败"
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package risk_control 提供风险控制中间件
|
||||
package risk_control
|
||||
|
||||
import (
|
||||
|
||||
@@ -15,8 +15,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package upload 提供文件上传与下载功能
|
||||
package upload
|
||||
|
||||
// 上传模块错误消息常量
|
||||
const (
|
||||
ErrNoFileSelected = "请选择要上传的文件"
|
||||
ErrInvalidUploadType = "无效的上传类型"
|
||||
|
||||
@@ -15,4 +15,5 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package common 提供跨模块共享的常量、错误定义和通用工具函数。
|
||||
package common
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
// 通用业务错误消息常量
|
||||
const (
|
||||
BannedAccount = "账号已被封禁"
|
||||
AmountMustBeGreaterThanZero = "金额必须大于0"
|
||||
@@ -32,6 +33,7 @@ const (
|
||||
UnAuthorized = "未登录"
|
||||
)
|
||||
|
||||
// 保护期相关错误消息
|
||||
const (
|
||||
GetProtectionDaysFailed = "获取新用户保护期配置失败"
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package idgen 提供分布式 ID 生成器
|
||||
package idgen
|
||||
|
||||
import (
|
||||
@@ -41,6 +42,7 @@ func init() {
|
||||
log.Printf("[Snowflake] initialized with node ID: %d, epoch: 2025-12-01\n", nodeID)
|
||||
}
|
||||
|
||||
// NextUint64ID 生成下一个分布式唯一 ID
|
||||
func NextUint64ID() uint64 {
|
||||
return uint64(node.Generate().Int64())
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ func buildDSN(host string, port int, username, password string) string {
|
||||
return pqURL.String()
|
||||
}
|
||||
|
||||
// DB 返回带上下文追踪的 GORM 数据库实例
|
||||
func DB(ctx context.Context) *gorm.DB {
|
||||
if db == nil {
|
||||
return nil
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// Redis 全局 Redis 客户端实例
|
||||
Redis redis.UniversalClient
|
||||
)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package logger 提供结构化日志封装
|
||||
package logger
|
||||
|
||||
const (
|
||||
|
||||
@@ -27,12 +27,14 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 认证源类型
|
||||
const (
|
||||
AuthSourceTypeOIDC = "oidc"
|
||||
)
|
||||
|
||||
var authSourceNamePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$`)
|
||||
|
||||
// AuthSource 认证源实体
|
||||
type AuthSource struct {
|
||||
ID uint64 `json:"id" gorm:"primaryKey"`
|
||||
Name string `json:"name" gorm:"uniqueIndex;size:80;not null"`
|
||||
@@ -49,6 +51,7 @@ type AuthSource struct {
|
||||
ClientSecretConfigured bool `json:"client_secret_configured" gorm:"-"`
|
||||
}
|
||||
|
||||
// ExternalAccount 外部账号绑定实体
|
||||
type ExternalAccount struct {
|
||||
ID uint64 `json:"id" gorm:"primaryKey"`
|
||||
AuthSourceID uint64 `json:"auth_source_id" gorm:"uniqueIndex:idx_external_accounts_source_external,priority:1;index"`
|
||||
@@ -60,6 +63,7 @@ type ExternalAccount struct {
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// ExternalAccountView 外部帐号绑定视图(脱敏展示用)
|
||||
type ExternalAccountView struct {
|
||||
ID uint64 `json:"id"`
|
||||
AuthSourceID uint64 `json:"auth_source_id"`
|
||||
@@ -71,6 +75,7 @@ type ExternalAccountView struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// Normalize 对认证源字段进行标准化处理
|
||||
func (source *AuthSource) Normalize() {
|
||||
source.Type = strings.ToLower(strings.TrimSpace(source.Type))
|
||||
source.Name = strings.TrimSpace(source.Name)
|
||||
@@ -88,6 +93,7 @@ func (source *AuthSource) Normalize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate 校验认证源字段合法性
|
||||
func (source *AuthSource) Validate() error {
|
||||
source.Normalize()
|
||||
if source.Name == "" {
|
||||
@@ -108,11 +114,13 @@ func (source *AuthSource) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sanitize 脱敏处理,将 ClientSecret 清空并设置 ClientSecretConfigured 标志
|
||||
func (source *AuthSource) Sanitize() {
|
||||
source.ClientSecretConfigured = source.ClientSecret != ""
|
||||
source.ClientSecret = ""
|
||||
}
|
||||
|
||||
// GetAuthSources 获取所有认证源(已脱敏)
|
||||
func GetAuthSources() ([]AuthSource, error) {
|
||||
var sources []AuthSource
|
||||
if err := db.DB(context.Background()).Order("id asc").Find(&sources).Error; err != nil {
|
||||
@@ -124,6 +132,7 @@ func GetAuthSources() ([]AuthSource, error) {
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
// GetActiveAuthSources 获取所有已启用的认证源(已脱敏)
|
||||
func GetActiveAuthSources() ([]AuthSource, error) {
|
||||
var sources []AuthSource
|
||||
if err := db.DB(context.Background()).Where("is_active = ?", true).Order("id asc").Find(&sources).Error; err != nil {
|
||||
@@ -135,6 +144,7 @@ func GetActiveAuthSources() ([]AuthSource, error) {
|
||||
return sources, nil
|
||||
}
|
||||
|
||||
// GetAuthSourceByID 根据 ID 获取认证源
|
||||
func GetAuthSourceByID(id uint64) (*AuthSource, error) {
|
||||
if id == 0 {
|
||||
return nil, errors.New(errAuthSourceIDRequired)
|
||||
@@ -147,6 +157,7 @@ func GetAuthSourceByID(id uint64) (*AuthSource, error) {
|
||||
return &source, nil
|
||||
}
|
||||
|
||||
// GetAuthSourceByName 根据名称获取认证源
|
||||
func GetAuthSourceByName(name string) (*AuthSource, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
@@ -160,6 +171,7 @@ func GetAuthSourceByName(name string) (*AuthSource, error) {
|
||||
return &source, nil
|
||||
}
|
||||
|
||||
// CreateAuthSource 创建认证源
|
||||
func CreateAuthSource(source *AuthSource) error {
|
||||
if err := source.Validate(); err != nil {
|
||||
return err
|
||||
@@ -167,6 +179,7 @@ func CreateAuthSource(source *AuthSource) error {
|
||||
return db.DB(context.Background()).Create(source).Error
|
||||
}
|
||||
|
||||
// UpdateAuthSource 更新认证源,keepSecret 为 true 时保留原密钥
|
||||
func UpdateAuthSource(source *AuthSource, keepSecret bool) error {
|
||||
if source.ID == 0 {
|
||||
return errors.New(errAuthSourceIDRequired)
|
||||
@@ -194,6 +207,7 @@ func UpdateAuthSource(source *AuthSource, keepSecret bool) error {
|
||||
}).Error
|
||||
}
|
||||
|
||||
// ToggleAuthSource 切换认证源启用状态
|
||||
func ToggleAuthSource(id uint64, isActive bool) error {
|
||||
source, err := GetAuthSourceByID(id)
|
||||
if err != nil {
|
||||
@@ -206,6 +220,7 @@ func ToggleAuthSource(id uint64, isActive bool) error {
|
||||
return db.DB(context.Background()).Model(&AuthSource{}).Where("id = ?", id).Update("is_active", isActive).Error
|
||||
}
|
||||
|
||||
// DeleteAuthSource 删除认证源及其关联的外部帐号绑定
|
||||
func DeleteAuthSource(id uint64) error {
|
||||
if id == 0 {
|
||||
return errors.New(errAuthSourceIDRequired)
|
||||
@@ -218,6 +233,7 @@ func DeleteAuthSource(id uint64) error {
|
||||
})
|
||||
}
|
||||
|
||||
// FindExternalAccount 查找外部帐号绑定记录
|
||||
func FindExternalAccount(sourceID uint64, externalID string) (*ExternalAccount, error) {
|
||||
var account ExternalAccount
|
||||
if err := db.DB(context.Background()).Where("auth_source_id = ? AND external_id = ?", sourceID, externalID).First(&account).Error; err != nil {
|
||||
@@ -226,6 +242,7 @@ func FindExternalAccount(sourceID uint64, externalID string) (*ExternalAccount,
|
||||
return &account, nil
|
||||
}
|
||||
|
||||
// BindExternalAccount 绑定外部帐号(已存在时更新用户名和邮箱)
|
||||
func BindExternalAccount(account *ExternalAccount) error {
|
||||
if account.UserID == 0 || strings.TrimSpace(account.ExternalID) == "" {
|
||||
return errors.New(errExternalAccountBindingIncomplete)
|
||||
@@ -253,6 +270,7 @@ func BindExternalAccount(account *ExternalAccount) error {
|
||||
})
|
||||
}
|
||||
|
||||
// ListExternalAccountsByUserID 获取指定用户的所有外部帐号绑定视图
|
||||
func ListExternalAccountsByUserID(userID uint64) ([]ExternalAccountView, error) {
|
||||
if userID == 0 {
|
||||
return nil, errors.New(errUserIDRequired)
|
||||
@@ -294,6 +312,7 @@ func ListExternalAccountsByUserID(userID uint64) ([]ExternalAccountView, error)
|
||||
return views, nil
|
||||
}
|
||||
|
||||
// DeleteExternalAccountForUser 删除指定用户的外部帐号绑定
|
||||
func DeleteExternalAccountForUser(id uint64, userID uint64) error {
|
||||
if id == 0 || userID == 0 {
|
||||
return errors.New(errExternalAccountBindingIDRequired)
|
||||
|
||||
@@ -63,6 +63,7 @@ const (
|
||||
SystemConfigRedisHashKey = "system:system_configs"
|
||||
)
|
||||
|
||||
// SystemConfig 系统配置实体
|
||||
type SystemConfig struct {
|
||||
Key string `json:"key" gorm:"primaryKey;size:64;not null"`
|
||||
Value string `json:"value" gorm:"size:255;not null"`
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
// TaskExecutionStatus 任务执行状态
|
||||
type TaskExecutionStatus string
|
||||
|
||||
// 任务执行状态
|
||||
const (
|
||||
TaskExecutionStatusPending TaskExecutionStatus = "pending"
|
||||
TaskExecutionStatusRunning TaskExecutionStatus = "running"
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/internal/db"
|
||||
)
|
||||
|
||||
// Template 邮件/消息模板实体
|
||||
type Template struct {
|
||||
ID uint64 `json:"id" gorm:"primaryKey;autoIncrement"`
|
||||
Key string `json:"key" gorm:"uniqueIndex;size:80;not null"`
|
||||
@@ -41,6 +42,7 @@ type Template struct {
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime;index"`
|
||||
}
|
||||
|
||||
// Normalize 规范化模板字段
|
||||
func (t *Template) Normalize() {
|
||||
t.Key = strings.TrimSpace(t.Key)
|
||||
t.Name = strings.TrimSpace(t.Name)
|
||||
@@ -53,6 +55,7 @@ func (t *Template) Normalize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate 校验模板必填字段
|
||||
func (t *Template) Validate() error {
|
||||
t.Normalize()
|
||||
if t.Key == "" {
|
||||
@@ -67,6 +70,7 @@ func (t *Template) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Render 渲染模板的 Subject 和 Content
|
||||
func (t *Template) Render(data any) (string, string, error) {
|
||||
// Render Subject
|
||||
var subject string
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
// UploadStatus 上传状态
|
||||
type UploadStatus string
|
||||
|
||||
// 上传状态
|
||||
const (
|
||||
UploadStatusPending UploadStatus = "pending" // 待使用
|
||||
UploadStatusUsed UploadStatus = "used" // 已使用
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package otel_trace 提供 OpenTelemetry 链路追踪封装工具
|
||||
package otel_trace
|
||||
|
||||
import "go.opentelemetry.io/otel/propagation"
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Tracer 全局 OpenTelemetry Tracer 实例
|
||||
var Tracer trace.Tracer
|
||||
var shutdownFuncs []func(context.Context) error
|
||||
|
||||
@@ -45,6 +46,7 @@ func init() {
|
||||
Tracer = tracerProvider.Tracer("github.com/Rain-kl/Wavelet")
|
||||
}
|
||||
|
||||
// Shutdown 关闭所有 Trace Provider
|
||||
func Shutdown(ctx context.Context) {
|
||||
for _, fn := range shutdownFuncs {
|
||||
_ = fn(ctx)
|
||||
@@ -52,6 +54,7 @@ func Shutdown(ctx context.Context) {
|
||||
shutdownFuncs = nil
|
||||
}
|
||||
|
||||
// Start 创建一个新的 Trace Span
|
||||
func Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
||||
return Tracer.Start(ctx, name, opts...)
|
||||
}
|
||||
|
||||
@@ -14,14 +14,17 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package storage 提供文件存储抽象层,包括 S3 兼容存储和本地缓存。
|
||||
package storage
|
||||
|
||||
// ErrS3InitializationFailed S3 存储初始化失败错误
|
||||
type ErrS3InitializationFailed struct{}
|
||||
|
||||
func (e ErrS3InitializationFailed) Error() string {
|
||||
return errS3InitializationFailed
|
||||
}
|
||||
|
||||
// LocalCacheError 本地缓存错误
|
||||
type LocalCacheError struct{}
|
||||
|
||||
func (e LocalCacheError) Error() string {
|
||||
|
||||
@@ -75,10 +75,12 @@ func init() {
|
||||
log.Printf("[Storage] S3 storage initialized (bucket: %s, prefix: %s, cdn: %s)\n", bucket, keyPrefix, cdnURL)
|
||||
}
|
||||
|
||||
// IsEnabledFunc 检查 S3 存储是否已初始化(可替换用于测试)
|
||||
var IsEnabledFunc = func() bool {
|
||||
return client != nil
|
||||
}
|
||||
|
||||
// IsEnabled 检查 S3 存储是否可用
|
||||
func IsEnabled() bool {
|
||||
return IsEnabledFunc()
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package task
|
||||
import "context"
|
||||
|
||||
// TaskResult 任务执行结果
|
||||
//nolint:revive // TaskResult 保留完整名称以避免与通用 Result 混淆
|
||||
type TaskResult struct {
|
||||
Message string // 结果摘要,如 "共清理 120 个文件,耗时 3.2s"
|
||||
Detail string // 可选的详细结果 JSON
|
||||
@@ -37,6 +38,8 @@ type PayloadValidator interface {
|
||||
//
|
||||
// 开发者只需实现 Execute 方法编写业务逻辑,在方法内通过 task.AppendLog(ctx, ...) 追加执行日志。
|
||||
// 任务的创建、状态更新、错误记录、重试计数全部由框架透明处理。
|
||||
//
|
||||
//nolint:revive // TaskHandler 保留完整名称以避免与通用 Handler 混淆
|
||||
type TaskHandler interface {
|
||||
// Execute 执行任务业务逻辑
|
||||
// - ctx: 已注入 Trace Span 和 taskID 的上下文
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package handlers 注册异步任务处理器
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package scheduler 提供定时任务调度功能
|
||||
package scheduler
|
||||
|
||||
const (
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package worker 提供 Asynq 任务处理服务器与中间件
|
||||
package worker
|
||||
|
||||
import (
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package testhelper 提供测试辅助工具
|
||||
package testhelper
|
||||
|
||||
import (
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
)
|
||||
|
||||
// fnv1a returns the 32-bit FNV-1a hash of a string
|
||||
//
|
||||
//nolint:mnd // FNV-1a 算法位移常量
|
||||
func fnv1a(str string) uint32 {
|
||||
var hash uint32 = 2166136261
|
||||
for i := 0; i < len(str); i++ {
|
||||
@@ -32,6 +34,8 @@ func fnv1a(str string) uint32 {
|
||||
}
|
||||
|
||||
// fnv1aResume resumes FNV-1a hashing from a given state
|
||||
//
|
||||
//nolint:mnd // FNV-1a 算法位移常量
|
||||
func fnv1aResume(state uint32, str string) uint32 {
|
||||
h := state
|
||||
for i := 0; i < len(str); i++ {
|
||||
@@ -42,6 +46,8 @@ func fnv1aResume(state uint32, str string) uint32 {
|
||||
}
|
||||
|
||||
// prngFromHash generates a hex string of specified length using an initial hash state
|
||||
//
|
||||
//nolint:mnd // xorshift 算法位移常量
|
||||
func prngFromHash(initialHash uint32, length int) string {
|
||||
state := initialHash
|
||||
var result strings.Builder
|
||||
|
||||
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package util 提供通用工具函数
|
||||
package util
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
// StringArray custom type for handling JSON arrays
|
||||
type StringArray []string
|
||||
|
||||
// Scan 实现 sql.Scanner 接口,从数据库读取 JSON 数组
|
||||
func (sa *StringArray) Scan(value interface{}) error {
|
||||
bytesValue, ok := value.([]byte)
|
||||
if !ok {
|
||||
@@ -34,6 +35,7 @@ func (sa *StringArray) Scan(value interface{}) error {
|
||||
return json.Unmarshal(bytesValue, sa)
|
||||
}
|
||||
|
||||
// Value 实现 driver.Valuer 接口,将 JSON 数组序列化为数据库存储值
|
||||
func (sa StringArray) Value() (driver.Value, error) {
|
||||
return json.Marshal(sa)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package mail 提供 SMTP 邮件发送功能。
|
||||
package mail
|
||||
|
||||
const (
|
||||
|
||||
@@ -18,6 +18,7 @@ package util
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
|
||||
// HashPassword 使用 bcrypt 对密码进行哈希处理
|
||||
func HashPassword(password string) (string, error) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
@@ -26,6 +27,7 @@ func HashPassword(password string) (string, error) {
|
||||
return string(hash), nil
|
||||
}
|
||||
|
||||
// CheckPasswordHash 比较 bcrypt 哈希值与明文密码是否匹配
|
||||
func CheckPasswordHash(hash, password string) bool {
|
||||
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user