Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["realname_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"alipay.go",
"antispam.go",
"data.go",
"geetest.go",
"realname.go",
"upload.go",
],
importpath = "go-common/app/interface/main/account/service/realname",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/realname:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/interface/main/account/service/realname/crypto:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/account/service/realname/crypto:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,219 @@
package realname
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/url"
"regexp"
"time"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
memmodel "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
var (
_idCard18Regexp = regexp.MustCompile(`^\d{17}[\d|x]$`)
_idCard15Regexp = regexp.MustCompile(`^\d{15}$`)
)
// AlipayApply 提交芝麻认证申请
func (s *Service) AlipayApply(c context.Context, mid int64, param *model.ParamRealnameAlipayApply) (res *model.RealnameAlipayApply, err error) {
if !s.alipayAntispamCheck(c, mid) {
err = ecode.RealnameAlipayAntispam
return
}
if !s.checkID(param.CardNum) {
err = ecode.RealnameCardNumErr
return
}
var bizno string
if bizno, err = s.alipayInit(c, param.Realname, param.CardNum); err != nil {
return
}
res = &model.RealnameAlipayApply{}
if res.URL, err = s.alipayCertifyURL(c, bizno); err != nil {
return
}
var (
arg = &memmodel.ArgRealnameAlipayApply{
MID: mid,
CaptureCode: param.Capture,
Realname: param.Realname,
CardCode: param.CardNum,
IMGToken: param.ImgToken,
Bizno: bizno,
}
)
if err = s.memRPC.RealnameAlipayApply(c, arg); err != nil {
res = nil
return
}
s.addmiss(func() {
if missErr := s.alipayAntispamIncrease(context.Background(), mid); missErr != nil {
log.Error("%+v", err)
}
})
return
}
func (s *Service) checkID(card string) bool {
if !_idCard15Regexp.MatchString(card) && !_idCard18Regexp.MatchString(card) {
return false
}
return true
}
func (s *Service) alipayInit(c context.Context, realname, cardNum string) (bizno string, err error) {
var (
biz struct {
TransID string `json:"transaction_id"`
ProdCode string `json:"product_code"`
BizCode string `json:"biz_code"`
IdenParam struct {
IdentityType string `json:"identity_type"`
CertType string `json:"cert_type"`
CertName string `json:"cert_name"`
CertNo string `json:"cert_no"`
} `json:"identity_param"`
}
param url.Values
)
biz.TransID = s.alipayTransactionID() // 商户请求的唯一标志32位长度的字母数字下划线组合。该标识作为对账的关键信息商户要保证其唯一性.
biz.ProdCode = "w1010100000000002978" // 芝麻认证产品码
biz.BizCode = "FACE" // 认证场景码,支持的场景码有: FACE多因子活体人脸认证 SMART_FACE多因子快捷活体人脸认证 FACE_SDKSDK活体人脸认证 签约的协议决定了可以使用的场景
biz.IdenParam.IdentityType = "CERT_INFO"
biz.IdenParam.CertType = "IDENTITY_CARD"
biz.IdenParam.CertName = realname
biz.IdenParam.CertNo = cardNum
if param, err = s.alipayParam("zhima.customer.certification.initialize", biz, ""); err != nil {
return
}
if bizno, err = s.realnameDao.AlipayInit(c, param); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
if bizno == "" {
err = ecode.RealnameAlipayErr
return
}
return
}
func (s *Service) alipayCertifyURL(c context.Context, bizno string) (u string, err error) {
var (
param url.Values
biz struct {
Bizno string `json:"biz_no"`
}
)
biz.Bizno = bizno
if param, err = s.alipayParam("zhima.customer.certification.certify", biz, "bilibili://auth.zhima"); err != nil {
return
}
u = conf.Conf.Realname.Alipay.Gateway + "?" + param.Encode()
return
}
// AlipayConfirm 查询芝麻认证状态
func (s *Service) AlipayConfirm(c context.Context, mid int64) (res *model.RealnameAlipayConfirm, err error) {
var (
pass bool
reason string
rpcarg = &memmodel.ArgMemberMid{
Mid: mid,
}
rpcres *memmodel.RealnameAlipayInfo
)
if rpcres, err = s.memRPC.RealnameAlipayBizno(c, rpcarg); err != nil {
return
}
if pass, reason, err = s.alipayQuery(c, rpcres.Bizno); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
res = &model.RealnameAlipayConfirm{
Reason: reason,
}
if pass {
res.Passed = model.RealnameTrue
} else {
res.Passed = model.RealnameFalse
}
// rpc call
var (
rpcConfirmArg = &memmodel.ArgRealnameAlipayConfirm{
MID: mid,
Pass: pass,
Reason: reason,
}
)
if err = s.memRPC.RealnameAlipayConfirm(c, rpcConfirmArg); err != nil {
return
}
s.addmiss(func() {
if missErr := s.setAlipayAntispamPassFlag(context.Background(), mid, false); missErr != nil {
log.Error("%+v", err)
}
})
return
}
func (s *Service) alipayQuery(c context.Context, bizno string) (pass bool, reason string, err error) {
var (
param url.Values
biz struct {
Bizno string `json:"biz_no"`
}
)
biz.Bizno = bizno
if param, err = s.alipayParam("zhima.customer.certification.query", biz, ""); err != nil {
return
}
if pass, reason, err = s.realnameDao.AlipayQuery(c, param); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
return
}
// alipayParam 构造阿里请求parambiz为 biz_content struct
func (s *Service) alipayParam(method string, biz interface{}, returnURL string) (p url.Values, err error) {
var (
sign string
bizBytes []byte
)
if bizBytes, err = json.Marshal(biz); err != nil {
err = errors.WithStack(err)
return
}
p = url.Values{}
p.Set("app_id", conf.Conf.Realname.Alipay.AppID)
p.Set("method", method)
p.Set("charset", "utf-8")
p.Set("sign_type", "RSA2")
p.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
p.Set("version", "1.0")
p.Set("biz_content", string(bizBytes))
if returnURL != "" {
p.Set("return_url", returnURL)
}
if sign, err = s.alipayCryptor.SignParam(p); err != nil {
return
}
p.Set("sign", sign)
return
}
func (s *Service) alipayTransactionID() string {
return fmt.Sprintf("BILI%d%d", time.Now().UnixNano(), rand.Intn(100000))
}

View File

@@ -0,0 +1,63 @@
package realname
import (
"context"
"go-common/app/interface/main/account/conf"
dao "go-common/app/interface/main/account/dao/realname"
"go-common/library/log"
)
func (s *Service) alipayAntispamCheck(c context.Context, mid int64) bool {
var (
value *dao.AlipayAntispamValue
err error
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
log.Error("%+v", err)
return true
}
if value == nil {
return true
}
if value.Count() > conf.Conf.Realname.AlipayAntispamThreshold && !value.Pass() {
return false
}
return true
}
// alipayAntispamIncrease 增加用户申请计数
func (s *Service) alipayAntispamIncrease(c context.Context, mid int64) (err error) {
var (
value *dao.AlipayAntispamValue
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
return
}
if value == nil {
value = new(dao.AlipayAntispamValue)
}
value.IncreaseCount()
if err = s.realnameDao.SetAlipayAntispam(c, mid, value); err != nil {
return
}
return
}
// setAlipayAntispamPassFlag 更新用户通过标识位
func (s *Service) setAlipayAntispamPassFlag(c context.Context, mid int64, flag bool) (err error) {
var (
value *dao.AlipayAntispamValue
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
return
}
if value == nil {
value = new(dao.AlipayAntispamValue)
}
value.SetPass(flag)
if err = s.realnameDao.SetAlipayAntispam(c, mid, value); err != nil {
return
}
return
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["crypto_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"alipay.go",
"key.go",
"main.go",
],
importpath = "go-common/app/interface/main/account/service/realname/crypto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/pkg/errors:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,123 @@
package crypto
import (
stdcrypto "crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"net/url"
"sort"
"strings"
"github.com/pkg/errors"
)
// Alipay alipay cryptor
type Alipay struct {
aliPub []byte
biliPriv []byte
}
// NewAlipay is.
func NewAlipay(aliPub, biliPriv string) (a *Alipay) {
return &Alipay{
aliPub: ParsePublicKey(aliPub),
biliPriv: ParsePrivateKey(biliPriv),
}
}
func (e *Alipay) splitData(originalData []byte, packageSize int) (r [][]byte) {
var src = make([]byte, len(originalData))
copy(src, originalData)
r = make([][]byte, 0)
if len(src) <= packageSize {
return append(r, src)
}
for len(src) > 0 {
var p = src[:packageSize]
r = append(r, p)
src = src[packageSize:]
if len(src) <= packageSize {
r = append(r, src)
break
}
}
return r
}
// EncryptParam rsa encrypt.
func (e *Alipay) EncryptParam(p url.Values) (ep string, err error) {
var (
pubInterface interface{}
pub *rsa.PublicKey
data []byte
block *pem.Block
)
block, _ = pem.Decode(e.aliPub)
if block == nil {
err = errors.New("private key error")
return
}
if pubInterface, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
pub = pubInterface.(*rsa.PublicKey)
var sd = e.splitData([]byte(p.Encode()), pub.N.BitLen()/8-11)
for _, d := range sd {
var pd []byte
if pd, err = rsa.EncryptPKCS1v15(rand.Reader, pub, d); err != nil {
err = errors.WithStack(err)
return
}
data = append(data, pd...)
}
ep = base64.StdEncoding.EncodeToString(data)
return
}
// SignParam sign alipay param
func (e *Alipay) SignParam(p url.Values) (sign string, err error) {
if p == nil {
p = make(url.Values)
}
var pList = make([]string, 0)
for key := range p {
var value = strings.TrimSpace(p.Get(key))
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
var h = stdcrypto.SHA256.New()
if _, err = h.Write([]byte(src)); err != nil {
err = errors.WithStack(err)
return
}
var (
hashed = h.Sum(nil)
pri *rsa.PrivateKey
data []byte
block *pem.Block
)
block, _ = pem.Decode(e.biliPriv)
if block == nil {
err = errors.New("private key error")
return
}
if pri, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
if data, err = rsa.SignPKCS1v15(rand.Reader, pri, stdcrypto.SHA256, hashed); err != nil {
err = errors.WithStack(err)
return
}
sign = base64.StdEncoding.EncodeToString(data)
return
}

View File

@@ -0,0 +1,40 @@
package crypto
import (
"bytes"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
var (
rsaBase64 = make([]byte, 1000)
aesBase64 = make([]byte, 5000000)
)
func TestEncrypt(t *testing.T) {
Convey("encrypt", t, func() {
// TODO
})
}
func BenchmarkBytesByFMT(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%04x%s%s", len(rsaBase64), rsaBase64, aesBase64)
}
}
func BenchmarkBytesByBuffer(b *testing.B) {
var buf bytes.Buffer
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Fprintf(&buf, "%04x", len(rsaBase64))
buf.Write(rsaBase64)
buf.Write(aesBase64)
b.StopTimer()
buf.Reset()
b.StartTimer()
_ = buf.Bytes()
}
}

View File

@@ -0,0 +1,47 @@
package crypto
import (
"bytes"
"strings"
)
// ParsePublicKey parse raw public key to pem formation
func ParsePublicKey(raw string) (result []byte) {
return parseKey(raw, "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")
}
// ParsePrivateKey parse raw priv key to pem formation
func ParsePrivateKey(raw string) (result []byte) {
return parseKey(raw, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----")
}
func parseKey(raw, prefix, suffix string) (result []byte) {
raw = strings.Replace(raw, prefix, "", 1)
raw = strings.Replace(raw, suffix, "", 1)
raw = strings.Replace(raw, " ", "", -1)
raw = strings.Replace(raw, "\n", "", -1)
raw = strings.Replace(raw, "\r", "", -1)
raw = strings.Replace(raw, "\t", "", -1)
var ll = 64
var sl = len(raw)
var c = sl / ll
if sl%ll > 0 {
c = c + 1
}
var buf bytes.Buffer
buf.WriteString(prefix + "\n")
for i := 0; i < c; i++ {
var b = i * ll
var e = b + ll
if e > sl {
buf.WriteString(raw[b:])
} else {
buf.WriteString(raw[b:e])
}
buf.WriteString("\n")
}
buf.WriteString(suffix)
return buf.Bytes()
}

View File

@@ -0,0 +1,208 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"fmt"
"strconv"
"time"
"github.com/pkg/errors"
)
// const .
const (
BlockSizeMIN = 16 // AES-128
BlockSizeMID = 24 // AES-192
BlockSizeMAX = 32 // AES-256
)
// Main mainsite cryptor
type Main struct {
publicKey, privateKey []byte
}
// NewMain is.
func NewMain(pub, priv string) (e *Main) {
return &Main{
publicKey: []byte(pub),
privateKey: []byte(priv),
}
}
// IMGEncrypt rsa + AES-128
func (e *Main) IMGEncrypt(raw []byte) (data []byte, err error) {
if len(raw) == 0 {
return
}
var (
hash = md5.New()
randToken []byte
rsaData, aesData []byte
aesBase64 []byte
rsaBase64Str string
buf bytes.Buffer
)
if _, err = hash.Write([]byte(strconv.FormatInt(time.Now().UnixNano(), 10))); err != nil {
err = errors.WithStack(err)
return
}
randToken = []byte(hex.EncodeToString(hash.Sum(nil)))
if rsaData, err = e.RsaEncrypt(randToken); err != nil {
err = errors.WithStack(err)
return
}
if aesData, err = e.AESEncrypt(randToken, raw, BlockSizeMIN); err != nil {
err = errors.WithStack(err)
return
}
rsaBase64Str = base64.StdEncoding.EncodeToString(rsaData)
aesBase64 = make([]byte, base64.StdEncoding.EncodedLen(len(aesData)))
base64.StdEncoding.Encode(aesBase64, aesData)
fmt.Fprintf(&buf, "%04x", len(rsaBase64Str))
buf.Write([]byte(rsaBase64Str))
buf.Write(aesBase64)
data = buf.Bytes()
return
}
// IMGDecrypt rsa + AES-128
func (e *Main) IMGDecrypt(raw []byte) (data []byte, err error) {
if len(raw) == 0 {
return
}
var (
rsaLen int64
rsaRandToken []byte
randToken []byte
aesBase64 []byte
aesData []byte
base64DecodedSize int
)
if rsaLen, err = strconv.ParseInt(string(raw[:4]), 16, 64); err != nil {
err = errors.WithStack(err)
return
}
if rsaRandToken, err = base64.StdEncoding.DecodeString(string(raw[4 : 4+rsaLen])); err != nil {
err = errors.WithStack(err)
return
}
if randToken, err = e.RsaDecrypt(rsaRandToken); err != nil {
err = errors.WithStack(err)
return
}
aesBase64 = raw[4+rsaLen:]
aesData = make([]byte, base64.StdEncoding.DecodedLen(len(aesBase64)))
if base64DecodedSize, err = base64.StdEncoding.Decode(aesData, aesBase64); err != nil {
err = errors.WithStack(err)
return
}
if data, err = e.AESDecrypt(randToken, aesData[:base64DecodedSize], BlockSizeMIN); err != nil {
err = errors.WithStack(err)
return
}
return
}
// RsaEncrypt rsa encrypt.
func (e *Main) RsaEncrypt(text []byte) (data []byte, err error) {
var (
block *pem.Block
)
block, _ = pem.Decode(e.publicKey)
if block == nil {
return nil, errors.New("public key error")
}
var (
pubInterface interface{}
pub *rsa.PublicKey
)
if pubInterface, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return nil, err
}
pub = pubInterface.(*rsa.PublicKey)
if data, err = rsa.EncryptPKCS1v15(rand.Reader, pub, text); err != nil {
err = errors.WithStack(err)
return
}
return
}
// RsaDecrypt rsa decrypt.
func (e *Main) RsaDecrypt(text []byte) (data []byte, err error) {
var (
block *pem.Block
)
block, _ = pem.Decode(e.privateKey)
if block == nil {
return nil, errors.New("private key error")
}
var (
privateKey *rsa.PrivateKey
)
if privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
if data, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, text); err != nil {
err = errors.WithStack(err)
return
}
return
}
// AESEncrypt AES-128, AES-192, or AES-256 encrypt.
// mod 16, 24, or 32 bytes
func (e *Main) AESEncrypt(key, text []byte, mod int) (data []byte, err error) {
var (
block cipher.Block
)
if block, err = aes.NewCipher(key[:mod]); err != nil {
err = errors.WithStack(err)
return
}
msg := pkPadding(text, block.BlockSize())
ciphertext := make([]byte, len(msg))
cbc := cipher.NewCBCEncrypter(block, key[mod:])
cbc.CryptBlocks(ciphertext, []byte(msg))
return ciphertext, nil
}
// AESDecrypt AES-128, AES-192, or AES-256 decrypt.
// mod 16, 24, or 32 bytes
func (e *Main) AESDecrypt(key, text []byte, mod int) (data []byte, err error) {
var (
block cipher.Block
)
if block, err = aes.NewCipher(key[:mod]); err != nil {
err = errors.WithStack(err)
return
}
blockModel := cipher.NewCBCDecrypter(block, key[mod:])
ciphertext := make([]byte, len(text))
blockModel.CryptBlocks(ciphertext, text)
ciphertext = pkUnPadding(ciphertext)
return ciphertext, nil
}
func pkPadding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(0)}, padding)
return append(src, padtext...)
}
func pkUnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}

View File

@@ -0,0 +1,251 @@
package realname
import (
"go-common/app/interface/main/account/model"
)
var (
cardTypeList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
{ID: 6, Name: "其他国家或地区身份证"},
}
// ios粉 <= 5.35版本兼容
cardTypeOldIOSList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 1, Name: "护照(境外签发)"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
{ID: 6, Name: "其他国家或地区身份证"},
}
// 兼容老版本的证件列表
cardTypeOldList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 1, Name: "护照(境外签发)"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
}
countryList = []*model.RealnameCountry{
// &model.RealnameCountry{ID: -1, CName: "---其他---"},
// &model.RealnameCountry{ID: 0, CName: "---常见---"},
{ID: 11, CName: "美国"},
{ID: 12, CName: "加拿大"},
{ID: 13, CName: "比利时"},
{ID: 14, CName: "法国"},
{ID: 15, CName: "澳大利亚"},
{ID: 16, CName: "日本"},
{ID: 17, CName: "新加坡"},
{ID: 18, CName: "韩国"},
{ID: 19, CName: "马来西亚"},
{ID: 20, CName: "英国"},
{ID: 21, CName: "意大利"},
{ID: 22, CName: "德国"},
{ID: 23, CName: "俄罗斯"},
{ID: 24, CName: "新西兰"},
{ID: 25, CName: "阿尔巴尼亚"},
{ID: 26, CName: "阿尔及利亚"},
{ID: 27, CName: "阿富汗"},
{ID: 28, CName: "阿根廷"},
{ID: 29, CName: "阿联酋"},
{ID: 30, CName: "阿曼"},
{ID: 31, CName: "阿塞拜疆"},
{ID: 32, CName: "埃及"},
{ID: 33, CName: "埃塞俄比亚"},
{ID: 34, CName: "爱尔兰"},
{ID: 35, CName: "爱沙尼亚"},
{ID: 36, CName: "安道尔"},
{ID: 37, CName: "安哥拉"},
{ID: 38, CName: "安提瓜岛和巴布达"},
{ID: 39, CName: "奥地利"},
{ID: 40, CName: "巴巴多斯"},
{ID: 41, CName: "巴布亚新几内亚"},
{ID: 42, CName: "巴哈马群岛"},
{ID: 43, CName: "巴基斯坦"},
{ID: 44, CName: "巴拉圭"},
{ID: 45, CName: "巴林"},
{ID: 46, CName: "巴拿马"},
{ID: 47, CName: "巴西"},
{ID: 48, CName: "白俄罗斯"},
{ID: 49, CName: "百慕大群岛"},
{ID: 50, CName: "保加利亚"},
{ID: 51, CName: "贝宁"},
{ID: 52, CName: "冰岛"},
{ID: 53, CName: "波多黎各"},
{ID: 54, CName: "波黑"},
{ID: 55, CName: "波兰"},
{ID: 56, CName: "玻利维亚"},
{ID: 57, CName: "伯利兹"},
{ID: 58, CName: "博茨瓦纳"},
{ID: 59, CName: "不丹"},
{ID: 60, CName: "布基纳法索"},
{ID: 61, CName: "布隆迪"},
{ID: 62, CName: "赤道几内亚"},
{ID: 63, CName: "丹麦"},
{ID: 64, CName: "迪戈加西亚岛"},
{ID: 65, CName: "多哥"},
{ID: 66, CName: "多米尼加"},
{ID: 67, CName: "多米尼加代表"},
{ID: 68, CName: "厄瓜多尔"},
{ID: 69, CName: "厄立特里亚"},
{ID: 70, CName: "法罗岛"},
{ID: 71, CName: "法属波利尼西亚"},
{ID: 72, CName: "法属圭亚那"},
{ID: 73, CName: "非洲中部"},
{ID: 74, CName: "菲律宾"},
{ID: 75, CName: "斐济"},
{ID: 76, CName: "芬兰"},
{ID: 77, CName: "佛得角"},
{ID: 78, CName: "福克兰岛"},
{ID: 79, CName: "冈比亚"},
{ID: 80, CName: "刚果"},
{ID: 81, CName: "刚果CName:(金)"},
{ID: 82, CName: "哥伦比亚"},
{ID: 83, CName: "哥斯达黎加"},
{ID: 84, CName: "格林纳达"},
{ID: 85, CName: "格陵兰岛"},
{ID: 86, CName: "古巴"},
{ID: 87, CName: "瓜德罗普岛"},
{ID: 88, CName: "关岛"},
{ID: 89, CName: "海地"},
{ID: 90, CName: "韩国"},
{ID: 91, CName: "荷兰"},
{ID: 92, CName: "洪都拉斯"},
{ID: 93, CName: "维克岛"},
{ID: 94, CName: "基里巴斯"},
{ID: 95, CName: "吉布提"},
{ID: 96, CName: "吉尔吉斯斯坦"},
{ID: 97, CName: "几内亚"},
{ID: 98, CName: "几内亚比绍"},
{ID: 99, CName: "加纳"},
{ID: 100, CName: "加蓬"},
{ID: 101, CName: "柬埔寨"},
{ID: 102, CName: "捷克"},
{ID: 103, CName: "津巴布韦"},
{ID: 104, CName: "聚会岛"},
{ID: 105, CName: "喀麦隆"},
{ID: 106, CName: "卡塔尔"},
{ID: 107, CName: "开曼群岛"},
{ID: 108, CName: "科摩罗"},
{ID: 109, CName: "科威特"},
{ID: 110, CName: "克罗地亚"},
{ID: 111, CName: "肯尼亚"},
{ID: 112, CName: "库克岛"},
{ID: 113, CName: "拉脱维亚"},
{ID: 114, CName: "莱索托"},
{ID: 115, CName: "老挝"},
{ID: 116, CName: "黎巴嫩"},
{ID: 117, CName: "立陶宛"},
{ID: 118, CName: "利比里亚"},
{ID: 119, CName: "利比亚"},
{ID: 120, CName: "卢森堡"},
{ID: 121, CName: "卢旺达"},
{ID: 122, CName: "罗马尼亚"},
{ID: 123, CName: "马达加斯加"},
{ID: 124, CName: "马尔代夫"},
{ID: 125, CName: "马耳他"},
{ID: 126, CName: "马拉维"},
{ID: 127, CName: "马里"},
{ID: 128, CName: "马里亚纳岛"},
{ID: 129, CName: "马其顿"},
{ID: 130, CName: "马提尼克岛"},
{ID: 131, CName: "马歇尔岛"},
{ID: 132, CName: "毛里求斯"},
{ID: 133, CName: "毛利塔尼亚"},
{ID: 134, CName: "蒙古"},
{ID: 135, CName: "蒙特塞拉特岛"},
{ID: 136, CName: "孟加拉国"},
{ID: 137, CName: "秘鲁"},
{ID: 138, CName: "密克罗尼西亚"},
{ID: 139, CName: "缅甸"},
{ID: 140, CName: "摩尔多瓦"},
{ID: 141, CName: "摩洛哥"},
{ID: 142, CName: "摩纳哥"},
{ID: 143, CName: "莫桑比克"},
{ID: 144, CName: "墨西哥"},
{ID: 145, CName: "纳米比亚"},
{ID: 146, CName: "南非"},
{ID: 147, CName: "南斯拉夫"},
{ID: 148, CName: "瑙鲁"},
{ID: 149, CName: "尼泊尔"},
{ID: 150, CName: "尼加拉瓜"},
{ID: 151, CName: "尼日尔"},
{ID: 152, CName: "尼日利亚"},
{ID: 153, CName: "纽埃岛"},
{ID: 154, CName: "挪威"},
{ID: 155, CName: "诺福克岛"},
{ID: 156, CName: "帕劳"},
{ID: 157, CName: "葡萄牙"},
{ID: 158, CName: "瓦利斯群岛和富图纳群岛"},
{ID: 159, CName: "格鲁吉亚"},
{ID: 160, CName: "瑞典"},
{ID: 161, CName: "瑞士"},
{ID: 162, CName: "萨尔瓦多"},
{ID: 163, CName: "萨摩亚、西部"},
{ID: 164, CName: "萨摩亚、东部"},
{ID: 165, CName: "塞拉利昂"},
{ID: 166, CName: "塞内加尔"},
{ID: 167, CName: "塞浦路斯"},
{ID: 168, CName: "塞舌尔共和国"},
{ID: 169, CName: "桑给巴尔岛"},
{ID: 170, CName: "沙特阿拉伯"},
{ID: 171, CName: "圣多美和普林西比"},
{ID: 172, CName: "圣卢西亚"},
{ID: 173, CName: "圣马力诺"},
{ID: 174, CName: "圣皮埃尔和密克隆群岛"},
{ID: 175, CName: "斯里兰卡"},
{ID: 176, CName: "斯洛伐克"},
{ID: 177, CName: "斯洛文尼亚"},
{ID: 178, CName: "斯威士兰"},
{ID: 179, CName: "苏丹"},
{ID: 180, CName: "苏里南"},
{ID: 181, CName: "所罗门群岛"},
{ID: 182, CName: "索马里"},
{ID: 183, CName: "泰国"},
{ID: 184, CName: "坦桑尼亚"},
{ID: 185, CName: "汤加"},
{ID: 186, CName: "特克斯和凯科斯"},
{ID: 187, CName: "特立尼达和多巴哥"},
{ID: 188, CName: "阿森松岛"},
{ID: 189, CName: "突尼斯"},
{ID: 190, CName: "图瓦卢"},
{ID: 191, CName: "土耳其"},
{ID: 192, CName: "土库曼斯坦"},
{ID: 193, CName: "托克劳岛"},
{ID: 194, CName: "瓦努阿图"},
{ID: 195, CName: "维珍群岛:(美属)"},
{ID: 196, CName: "维珍群岛:(英属)"},
{ID: 197, CName: "委内瑞拉"},
{ID: 198, CName: "文莱"},
{ID: 199, CName: "乌干达"},
{ID: 200, CName: "乌克兰"},
{ID: 201, CName: "乌拉圭"},
{ID: 202, CName: "乌兹别克斯坦"},
{ID: 203, CName: "西班牙"},
{ID: 204, CName: "希腊"},
{ID: 205, CName: "科特迪瓦"},
{ID: 206, CName: "匈牙利"},
{ID: 207, CName: "叙利亚"},
{ID: 208, CName: "牙买加"},
{ID: 209, CName: "亚美尼亚"},
{ID: 210, CName: "也门"},
{ID: 211, CName: "伊拉克"},
{ID: 212, CName: "伊朗"},
{ID: 213, CName: "以色列"},
{ID: 214, CName: "印度"},
{ID: 215, CName: "印尼"},
{ID: 216, CName: "约旦"},
{ID: 217, CName: "越南"},
{ID: 218, CName: "赞比亚"},
{ID: 219, CName: "乍得"},
{ID: 220, CName: "直布罗陀"},
{ID: 221, CName: "智利"},
}
)

View File

@@ -0,0 +1,99 @@
package realname
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"math/rand"
"net/url"
"strconv"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
)
// CaptchaGTRegister register geetest
func (s *Service) CaptchaGTRegister(c context.Context, mid int64, ip, gtType string) (urlstr string, remote int, err error) {
var (
p = url.Values{}
challenge string
)
p.Set("ct", "1")
p.Set("gt", conf.Conf.Realname.Geetest.CaptchaID)
if challenge, err = s.realnameDao.RealnameCaptchaGTRegister(c, mid, ip, gtType, 1); err != nil || challenge == "" {
p.Set("success", "0")
remote = 0
err = nil
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
p.Set("challenge", hex.EncodeToString(randOne[:])+hex.EncodeToString(randTwo[:])[0:2])
} else {
p.Set("success", "1")
remote = 1
array := md5.Sum([]byte(challenge + conf.Conf.Realname.Geetest.PrivateKey))
p.Set("challenge", hex.EncodeToString(array[:]))
}
p.Set("hash", fmt.Sprintf("%x", md5.Sum([]byte(p.Encode()))))
urlstr = "http://passport.bilibili.com/register/verification.html?" + p.Encode()
return
}
// CaptchaGTRefresh refresh geetest
func (s *Service) CaptchaGTRefresh(c context.Context, mid int64, ip, gtType string, hash string) (challenge string, gt string, success int, err error) {
log.Info("CaptchaGTRefresh got hash : %s", hash)
gt = conf.Conf.Realname.Geetest.CaptchaID
if challenge, err = s.realnameDao.RealnameCaptchaGTRegister(c, mid, ip, gtType, 1); err != nil || challenge == "" {
success = 0
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
challenge = hex.EncodeToString(randOne[:]) + hex.EncodeToString(randTwo[:])[0:2]
} else {
success = 1
array := md5.Sum([]byte(challenge + conf.Conf.Realname.Geetest.PrivateKey))
challenge = hex.EncodeToString(array[:])
}
return
}
// CaptchaGTValidate validate geetest
func (s *Service) CaptchaGTValidate(c context.Context, mid int64, ip, clientType string, param *model.ParamRealnameCaptchaGTCheck) (res *model.RealnameCaptchaGTValidate, err error) {
res = &model.RealnameCaptchaGTValidate{
State: model.RealnameFalse,
}
switch param.Remote {
// 极验远程校验
case model.RealnameTrue:
md5Array := md5.Sum([]byte(conf.Conf.Realname.Geetest.PrivateKey + "geetest" + param.Challenge))
if hex.EncodeToString(md5Array[:]) != param.Validate {
return
}
var remoteSeccode string
if remoteSeccode, err = s.realnameDao.RealnameCaptchaGTRegisterValidate(c, param.Challenge, param.Seccode, clientType, ip, conf.Conf.Realname.Geetest.CaptchaID, mid); err != nil {
return
}
log.Info("CaptchaGTValidate remoteSec : %s", remoteSeccode)
md5Array = md5.Sum([]byte(remoteSeccode))
res.State = model.RealnameTrue
// if hex.EncodeToString(md5Array[:]) == param.Seccode {
// res.State = model.RealnameTrue
// }
// 极验本地校验
case model.RealnameFalse:
// md5Array := md5.Sum([]byte(param.Challenge))
// if hex.EncodeToString(md5Array[:]) == param.Validate {
// res.State = model.RealnameTrue
// }
res.State = model.RealnameTrue
default:
err = ecode.RequestErr
}
s.addmiss(func() {
if missErr := s.setAlipayAntispamPassFlag(context.Background(), mid, true); missErr != nil {
log.Error("%+v", err)
}
})
return
}

View File

@@ -0,0 +1,206 @@
package realname
import (
"context"
"strings"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/realname"
"go-common/app/interface/main/account/model"
"go-common/app/interface/main/account/service/realname/crypto"
memrpc "go-common/app/service/main/member/api/gorpc"
memmodel "go-common/app/service/main/member/model"
"go-common/library/log"
)
// Service is
type Service struct {
c *conf.Config
memRPC *memrpc.Service
realnameDao *realname.Dao
mainCryptor *crypto.Main
alipayCryptor *crypto.Alipay
missch chan func()
}
// New create service instance and return.
func New(c *conf.Config, rsapub, rsapriv, alipub, alibilipriv string) (s *Service) {
s = &Service{
c: c,
memRPC: memrpc.New(c.RPCClient2.Member),
realnameDao: realname.New(c),
mainCryptor: crypto.NewMain(rsapub, rsapriv),
alipayCryptor: crypto.NewAlipay(alipub, alibilipriv),
missch: make(chan func(), 1024),
}
go s.missproc()
return
}
// Status get status of realname
func (s *Service) Status(c context.Context, mid int64) (status int8, err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
res *memmodel.RealnameStatus
)
if res, err = s.memRPC.RealnameStatus(c, arg); err != nil {
return
}
status = int8(*res)
return
}
// ApplyStatus return realname apply status
func (s *Service) ApplyStatus(c context.Context, mid int64) (status int8, remark string, realname string, card string, err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
res *memmodel.RealnameApplyStatusInfo
)
if res, err = s.memRPC.RealnameApplyStatus(c, arg); err != nil {
return
}
status = int8(res.Status)
remark = res.Remark
realname, card = maskRealnameInfo(res.Realname, res.Card)
return
}
func maskRealnameInfo(realname, card string) (r, c string) {
var (
rStrs = strings.Split(realname, "")
cStrs = strings.Split(card, "")
)
if len(rStrs) > 0 {
r = "*" + strings.Join(rStrs[1:], "")
}
if len(cStrs) > 0 {
if len(cStrs) == 1 {
c = "*"
} else if len(cStrs) > 5 {
c = cStrs[0] + strings.Repeat("*", len(cStrs)-3) + strings.Join(cStrs[len(cStrs)-2:], "")
} else {
c = cStrs[0] + strings.Repeat("*", len(cStrs)-1)
}
}
return
}
// CountryList .
func (s *Service) CountryList(c context.Context) (list []*model.RealnameCountry, err error) {
list = countryList
return
}
// CardTypes .
func (s *Service) CardTypes(c context.Context, platform string, mobiapp string, device string, build int) (list []*model.RealnameCardType, err error) {
if (platform == "android" && build < 512000) || (platform == "ios" && build <= 5990) {
list = cardTypeOldList
return
}
// IOS粉暂返回 5.32 版本数据,待 5.36 IOS 重新接入后,根据 build 号,返回 cardTypeList
if platform == "ios" && mobiapp == "iphone" && device != "pad" {
list = cardTypeOldIOSList
return
}
list = cardTypeList
return
}
// CardTypesV2 .
func (s *Service) CardTypesV2(c context.Context) (list []*model.RealnameCardType, err error) {
list = cardTypeList
return
}
// TelCapture .
func (s *Service) TelCapture(c context.Context, mid int64) (err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
)
if err = s.memRPC.RealnameTelCapture(c, arg); err != nil {
return
}
return
}
// TelInfo .
func (s *Service) TelInfo(c context.Context, mid int64) (tel string, err error) {
if tel, err = s.realnameDao.TelInfo(c, mid); err != nil {
return
}
if len(tel) == 0 {
return
}
if len(tel) < 4 {
tel = tel[:1] + "****"
return
}
tel = tel[:3] + "****" + tel[len(tel)-4:]
return
}
// Apply .
func (s *Service) Apply(c context.Context, mid int64, realname string, cardType int, cardNum string, countryID int, captureCode int, handIMGToken, frontIMGToken, backIMGToken string) (err error) {
var (
arg = &memmodel.ArgRealnameApply{
MID: mid,
CaptureCode: captureCode,
Realname: realname,
CardType: int8(cardType),
CardCode: cardNum,
Country: int16(countryID),
HandIMGToken: handIMGToken,
FrontIMGToken: frontIMGToken,
BackIMGToken: backIMGToken,
}
)
if err = s.memRPC.RealnameApply(c, arg); err != nil {
return
}
return
}
// Channel .
func (s *Service) Channel(c context.Context) (channels []*model.RealnameChannel, err error) {
for _, c := range conf.Conf.Realname.Channel {
var (
channel = &model.RealnameChannel{
Name: c.Name,
Flag: model.RealnameFalse,
}
)
if c.Flag {
channel.Flag = model.RealnameTrue
}
channels = append(channels, channel)
}
return
}
func (s *Service) addmiss(f func()) {
select {
case s.missch <- f:
default:
log.Error("eventproc chan full")
}
}
// missproc is a routine for executing closure.
func (s *Service) missproc() {
defer func() {
if x := recover(); x != nil {
log.Error("missproc panic %+v", x)
}
go s.missproc()
}()
for {
f := <-s.missch
f()
}
}

View File

@@ -0,0 +1,189 @@
package realname
import (
"context"
"flag"
"io/ioutil"
"os"
"testing"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
ctx = context.Background()
rsaPub, rsaPriv = ``, ``
alipayPub = ``
alipayOwnPriv = ``
)
func TestMain(m *testing.M) {
var err error
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf, rsaPub, rsaPriv, alipayPub, alipayOwnPriv)
m.Run()
os.Exit(0)
}
func TestEncrypt(t *testing.T) {
var (
raw []byte
err error
)
if raw, err = ioutil.ReadFile("./test.jpg"); err != nil {
panic(err)
}
Convey("encrypt", t, func() {
var (
encrpted []byte
outputs []byte
)
if encrpted, err = s.mainCryptor.IMGEncrypt(raw); err != nil {
panic(err)
}
if err = ioutil.WriteFile("./encrypted", encrpted, os.ModePerm); err != nil {
panic(err)
}
if outputs, err = s.mainCryptor.IMGDecrypt(encrpted); err != nil {
panic(err)
}
if err = ioutil.WriteFile("./output.jpg", outputs, os.ModePerm); err != nil {
panic(err)
}
})
}
func TestRealname(t *testing.T) {
Convey("realname", t, func() {
var (
mid int64
err error
)
_, err = s.TelInfo(ctx, mid)
So(err, ShouldBeNil)
err = s.TelCapture(ctx, mid)
So(err, ShouldBeNil)
s.CountryList(ctx)
s.CardTypes(ctx, "pc", "", "", 1234)
})
}
func TestRealnameMask(t *testing.T) {
Convey("realname mask", t, func() {
var (
realname1 = ""
realname2 = "托"
realname3 = "托米"
realname4 = "托了一地的米"
card1 = ""
card2 = "t"
card3 = "tom"
card4 = "tommmmmy233"
)
r, c := maskRealnameInfo(realname1, card1)
So(r, ShouldEqual, "")
So(c, ShouldEqual, "")
r, c = maskRealnameInfo(realname2, card2)
So(r, ShouldEqual, "*")
So(c, ShouldEqual, "*")
r, c = maskRealnameInfo(realname3, card3)
So(r, ShouldEqual, "*米")
So(c, ShouldEqual, "t**")
r, c = maskRealnameInfo(realname4, card4)
So(r, ShouldEqual, "*了一地的米")
So(c, ShouldEqual, "t********33")
})
}
func TestAlipay(t *testing.T) {
Convey("alipay", t, func() {
// bizno, err := s.alipayInit(context.Background(), "沐阳", "340702199110120011")
// So(err, ShouldBeNil)
// t.Log(bizno)
// url, err := s.alipayCertifyURL(context.Background(), conf.Conf.Realname.Alipay.AppID, bizno)
// So(err, ShouldBeNil)
// t.Log(url)
bizno := "ZM201808153000000757500643766753"
pass, reason, err := s.alipayQuery(context.Background(), bizno)
So(err, ShouldBeNil)
t.Log(pass, reason)
})
}
func TestGeetest(t *testing.T) {
Convey("gt", t, func() {
var (
mid int64 = 111001723
)
// urlStr, err := s.CaptchaGTRegister(ctx, mid, "127.0.0.1", "h5")
// So(err, ShouldBeNil)
// t.Log(urlStr)
// challenge, gt, success, err := s.CaptchaGTRefresh(ctx, mid, "127.0.0.1", "h5", "fake hash")
// So(err, ShouldBeNil)
// t.Log(challenge, gt, success)
var (
validateArg = &model.ParamRealnameCaptchaGTCheck{
Remote: 1,
Challenge: "58fb29d758ef977717b8fd98d5d1371b9c",
Validate: "6171ad7e1243a50c8ca9b124cb6ae411",
Seccode: "6171ad7e1243a50c8ca9b124cb6ae411|jordan",
}
)
res, err := s.CaptchaGTValidate(ctx, mid, "127.0.0.1", "h5", validateArg)
So(err, ShouldBeNil)
t.Log(res)
})
}
func BenchmarkEncrypt(b *testing.B) {
var (
err error
raw []byte
)
if raw, err = ioutil.ReadFile("./test.jpg"); err != nil {
panic(err)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err = s.mainCryptor.IMGEncrypt(raw); err != nil {
panic(err)
}
}
})
}
func BenchmarkDecrypt(b *testing.B) {
var (
err error
raw []byte
)
if raw, err = ioutil.ReadFile("./encrypted"); err != nil {
panic(err)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err = s.mainCryptor.IMGDecrypt(raw); err != nil {
panic(err)
}
}
})
}

View File

@@ -0,0 +1,130 @@
package realname
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"math/rand"
"os"
"strconv"
"strings"
"syscall"
"time"
"github.com/pkg/errors"
)
// Upload upload ID card.
func (s *Service) Upload(c context.Context, mid int64, data []byte) (src string, err error) {
var (
md5Engine = md5.New()
hashMID string
hashRand string
fileName string
dirPath string
dateStr string
)
md5Engine.Write([]byte(strconv.FormatInt(mid, 10)))
hashMID = hex.EncodeToString(md5Engine.Sum(nil))
md5Engine.Reset()
md5Engine.Write([]byte(strconv.FormatInt(time.Now().Unix(), 10)))
md5Engine.Write([]byte(strconv.FormatInt(rand.Int63n(1000000), 10)))
hashRand = hex.EncodeToString(md5Engine.Sum(nil))
fileName = fmt.Sprintf("%s_%s.txt", hashMID[:6], hashRand)
dateStr = time.Now().Format("20060102")
dirPath = fmt.Sprintf("%s/%s/", s.c.Realname.DataDir, dateStr)
var (
dataFile *os.File
writeFileSize int
encrptedData []byte
)
_, err = os.Stat(dirPath)
if os.IsNotExist(err) {
mask := syscall.Umask(0)
defer syscall.Umask(mask)
if err = os.MkdirAll(dirPath, 0777); err != nil {
err = errors.WithStack(err)
return
}
}
if encrptedData, err = s.mainCryptor.IMGEncrypt(data); err != nil {
err = errors.WithStack(err)
return
}
if dataFile, err = os.Create(dirPath + fileName); err != nil {
err = errors.Wrapf(err, "create file %s failed", dirPath+fileName)
return
}
defer dataFile.Close()
if writeFileSize, err = dataFile.Write(encrptedData); err != nil {
err = errors.Wrapf(err, "write file %s size %d failed", dirPath+fileName, len(encrptedData))
return
}
if writeFileSize != len(encrptedData) {
err = errors.Errorf("Write file data to %s , expected %d actual %d", dirPath+fileName, len(encrptedData), writeFileSize)
return
}
src = fmt.Sprintf("%s/%s", dateStr, strings.TrimSuffix(fileName, ".txt"))
return
}
// Preview preview id card
func (s *Service) Preview(c context.Context, mid int64, src string) (img []byte, err error) {
var (
filePath string
file *os.File
fileInfo os.FileInfo
)
if !s.validateSrc(mid, src) {
err = errors.Errorf("Preview src %s invalid", src)
return
}
filePath = fmt.Sprintf("%s/%s.txt", s.c.Realname.DataDir, src)
fileInfo, err = os.Stat(filePath)
if os.IsNotExist(err) {
err = errors.WithStack(err)
return
}
if time.Since(fileInfo.ModTime()) > time.Duration(s.c.Realname.ImageExpire) {
err = errors.Errorf("Realname upload image %s expired %+v", filePath, s.c.Realname.ImageExpire)
return
}
if file, err = os.Open(filePath); err != nil {
err = errors.WithStack(err)
return
}
defer file.Close()
if img, err = ioutil.ReadAll(file); err != nil {
err = errors.WithStack(err)
return
}
return s.mainCryptor.IMGDecrypt(img)
}
func (s *Service) validateSrc(mid int64, src string) (ok bool) {
var (
paths []string
fileNames []string
)
if paths = strings.Split(src, "/"); len(paths) != 2 {
return
}
if fileNames = strings.Split(paths[1], "_"); len(fileNames) != 2 {
return
}
var (
hash = md5.New()
midHash string
)
hash.Write([]byte(strconv.FormatInt(mid, 10)))
midHash = hex.EncodeToString(hash.Sum(nil))[:6]
if midHash != fileNames[0] {
return
}
ok = true
return
}