223 lines
5.5 KiB
Go
223 lines
5.5 KiB
Go
package dao
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/md5"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"github.com/json-iterator/go"
|
|
"go-common/app/service/openplatform/anti-fraud/conf"
|
|
"go-common/app/service/openplatform/anti-fraud/model"
|
|
"go-common/library/cache/redis"
|
|
"go-common/library/ecode"
|
|
"go-common/library/log"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
//CheckSalesTime 检查售卖时间
|
|
func (d *Dao) CheckSalesTime(c context.Context, mid, itemID, salesTime, saleTimeOut int64) (err error) {
|
|
key := model.GetSalesLimitKey(mid)
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
|
|
var (
|
|
flag int64
|
|
data []byte
|
|
)
|
|
data, _ = redis.Bytes(conn.Do("GET", key))
|
|
json.Unmarshal(data, &flag)
|
|
if flag == 1 {
|
|
return ecode.AntiSalesTimeErr
|
|
}
|
|
if salesTime > time.Now().Unix() {
|
|
conn.Do("SET", key, 1, "EX", saleTimeOut)
|
|
return ecode.AntiSalesTimeErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//CheckIPChange 检查用户ip变更
|
|
func (d *Dao) CheckIPChange(c context.Context, mid int64, ip string, changeTime int64) (err error) {
|
|
key := model.GetIPChangeKey(mid)
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
|
|
var (
|
|
flag string
|
|
data []byte
|
|
)
|
|
data, _ = redis.Bytes(conn.Do("GET", key))
|
|
json.Unmarshal(data, &flag)
|
|
|
|
go func(c context.Context, key string, ip string) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
conn.Do("SET", key, ip, "EX", changeTime)
|
|
}(context.Background(), key, ip)
|
|
if flag != "" && flag != ip {
|
|
return ecode.AntiIPChangeLimit
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//CheckLimitNum 检查限制次数
|
|
func (d *Dao) CheckLimitNum(c context.Context, key string, num int64, pastTime int64) (err error) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
|
|
pastTime = pastTime * 1e9
|
|
currentTime := time.Now().UnixNano()
|
|
conn.Do("ZADD", key, currentTime, currentTime)
|
|
data, _ := redis.Int64(conn.Do("ZCOUNT", key, currentTime-pastTime, currentTime))
|
|
go func(c context.Context, key string, pastTime, currentTime int64, flag bool) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
conn.Do("EXPIRE", key, pastTime/1e9)
|
|
if flag {
|
|
conn.Do("ZREMRANGEBYRANK", key, 0, 0)
|
|
}
|
|
}(context.Background(), key, pastTime, currentTime, data > num)
|
|
if data > num {
|
|
return ecode.AntiLimitNumUpper
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//Voucher 凭证
|
|
func (d *Dao) Voucher(c context.Context, mid int64, ip string, itemID, customer, voucherType int64) (voucher string) {
|
|
s := make([]byte, 0)
|
|
buf := bytes.NewBuffer(s)
|
|
binary.Write(buf, binary.BigEndian, mid)
|
|
binary.Write(buf, binary.BigEndian, []byte(ip))
|
|
binary.Write(buf, binary.BigEndian, itemID)
|
|
binary.Write(buf, binary.BigEndian, customer)
|
|
binary.Write(buf, binary.BigEndian, voucherType)
|
|
binary.Write(buf, binary.BigEndian, time.Now().UnixNano())
|
|
digest := md5.Sum(buf.Bytes())
|
|
voucher = hex.EncodeToString(digest[:])
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
key := model.GetUserVoucherKey(mid, voucher, voucherType)
|
|
conn.Do("SET", key, 1, "EX", model.RedisUserVoucherKeyTimeOut)
|
|
return
|
|
}
|
|
|
|
//CheckVoucher 验证用户凭证,一次性
|
|
func (d *Dao) CheckVoucher(c context.Context, mid int64, voucher string, voucherType int64) (err error) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
key := model.GetUserVoucherKey(mid, voucher, voucherType)
|
|
data, _ := redis.Int64(conn.Do("INCR", key))
|
|
conn.Do("DEL", key)
|
|
if data < 2 {
|
|
return ecode.AntiCheckVoucherErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//IncrGeetestCount 统计一小时内极验的请求数
|
|
func (d *Dao) IncrGeetestCount(c context.Context) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
key := model.GetGeetestCountKey()
|
|
conn.Do("INCR", key)
|
|
conn.Do("EXPIRE", key, model.RedisGeetestCountKeyTimeOut)
|
|
}
|
|
|
|
//CheckGeetestCount 检查极验总数是否达到上限
|
|
func (d *Dao) CheckGeetestCount(c context.Context) (err error) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
key := model.GetGeetestCountKey()
|
|
var (
|
|
data []byte
|
|
count int64
|
|
)
|
|
data, _ = redis.Bytes(conn.Do("GET", key))
|
|
json.Unmarshal(data, &count)
|
|
if count > d.c.Geetest.Count {
|
|
log.Info("极验总数达到上限")
|
|
return ecode.AntiGeetestCountUpper
|
|
}
|
|
return
|
|
}
|
|
|
|
// CheckBlack 检测黑名单
|
|
func (d *Dao) CheckBlack(c context.Context, customerId, mid int64, clientIP string) (err error) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
|
|
midKey := model.GetMIDBlackKey(customerId, mid)
|
|
ipKey := model.GetIPBlackKey(customerId, clientIP)
|
|
|
|
data, err := redis.Int64s(conn.Do("MGET", midKey, ipKey))
|
|
|
|
if err != nil {
|
|
log.Info("获取黑名单出错 %s %s", midKey, ipKey)
|
|
return nil
|
|
}
|
|
|
|
for _, value := range data {
|
|
if value == 1 {
|
|
return ecode.AntiBlackErr
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PayShield 支付风控
|
|
func (d *Dao) PayShield(c context.Context, data *model.ShieldData) {
|
|
var res struct {
|
|
errno int64
|
|
msg string
|
|
data interface{}
|
|
}
|
|
|
|
params, err := jsoniter.Marshal(data)
|
|
if err != nil {
|
|
log.Info("json marshal err %v", err)
|
|
return
|
|
}
|
|
|
|
log.Info("req pay shield params %s", string(params))
|
|
|
|
req, err := http.NewRequest("POST", conf.Conf.URL.Shield, bytes.NewBuffer(params))
|
|
if err != nil {
|
|
log.Warn("new request err url %s, err %v", conf.Conf.URL.Shield, err)
|
|
return
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
err = d.client.Do(c, req, &res)
|
|
if err != nil || res.errno != 0 {
|
|
log.Warn("client do err url %s, err %v", conf.Conf.URL.Shield, err)
|
|
return
|
|
}
|
|
|
|
}
|
|
|
|
// SetexRedisKey 设置redis key
|
|
func (d *Dao) SetexRedisKey(c context.Context, key string, timeout int64) {
|
|
conn := d.redis.Get(c)
|
|
defer conn.Close()
|
|
|
|
conn.Do("SET", key, 1, "EX", timeout)
|
|
}
|
|
|
|
// AddPayData .
|
|
func (d *Dao) AddPayData(data *model.ShieldData) {
|
|
d.payData <- data
|
|
}
|
|
|
|
// SyncPayShield .
|
|
func (d *Dao) SyncPayShield(c context.Context) {
|
|
for {
|
|
data := <-d.payData
|
|
d.PayShield(c, data)
|
|
}
|
|
}
|