bilibili-backup/app/service/openplatform/anti-fraud/dao/risk.go
2019-04-22 02:59:20 +00:00

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)
}
}