package model import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "fmt" "strconv" "strings" "time" "go-common/app/admin/main/member/conf" memmdl "go-common/app/service/main/member/model" "go-common/library/log" xtime "go-common/library/time" "github.com/pkg/errors" ) // realname conf var var ( RealnameSalt = "biliidentification@#$%^&*()(*&^%$#" RealnameImgPrefix = "/idenfiles/" RealnameImgSuffix = ".txt" LogActionRealnameUnbind = "realname_unbind" LogActionRealnameBack = "realname_back" LogActionRealnameSubmit = "realname_submit" RealnameManagerLogID = 251 ) type realnameChannel string // RealnameChannle const ( ChannelMain realnameChannel = "main" ChannelAlipay realnameChannel = "alipay" ) func (ch realnameChannel) DBChannel() uint8 { switch ch { case ChannelMain: return 0 case ChannelAlipay: return 1 } return 0 } type realnameAction string // RealnameAction const ( RealnameActionPass realnameAction = "pass" RealnameActionReject realnameAction = "reject" ) // RealnameCardType is. type RealnameCardType string const ( cardTypeIdentityCard RealnameCardType = "identity_card" cardTypeForeignPassport RealnameCardType = "foreign_passport" //Mainland Travel Permit for Hong Kong and Macao Residents cardTypeHongkongMacaoPermit RealnameCardType = "hongkong_macao_travel_permit" //Mainland travel permit for Taiwan residents cardTypeTaiwanPermit RealnameCardType = "taiwan_travel_permit" cardTypeChinaPassport RealnameCardType = "china_passport" //Foreigner's Permanent Residence Card cardTypeForeignerPermanentResidenceCard RealnameCardType = "foreigner_permanent_residence_card" cardTypeForeignIdentityCard RealnameCardType = "foreign_identity_card" ) // RealnameApplyStatus is. type RealnameApplyStatus string // RealnameApplyStatus const ( RealnameApplyStateAll RealnameApplyStatus = "all" RealnameApplyStatePending RealnameApplyStatus = "pending" RealnameApplyStatePassed RealnameApplyStatus = "passed" RealnameApplyStateRejective RealnameApplyStatus = "rejective" RealnameApplyStateNone RealnameApplyStatus = "none" ) // DBStatus is. func (r RealnameApplyStatus) DBStatus() int { switch r { case RealnameApplyStatePending: return 0 case RealnameApplyStatePassed: return 1 case RealnameApplyStateRejective: return 2 default: return -1 } } // ArgRealnameList is. type ArgRealnameList struct { Channel realnameChannel `form:"channel" validate:"required"` MID int64 `form:"mid"` Card string `form:"card"` CardType RealnameCardType `form:"card_type"` Country int `form:"country"` OPName string `form:"op_name"` TSFrom int64 `form:"ts_from"` TSTo int64 `form:"ts_to"` State RealnameApplyStatus `form:"state"` PS int `form:"ps"` PN int `form:"pn"` IsDesc bool `form:"is_desc"` } // DBCardType return card_type store in db func (a *ArgRealnameList) DBCardType() int { switch a.CardType { case cardTypeIdentityCard: return 0 case cardTypeForeignPassport: return 1 case cardTypeHongkongMacaoPermit: return 2 case cardTypeTaiwanPermit: return 3 case cardTypeChinaPassport: return 4 case cardTypeForeignerPermanentResidenceCard: return 5 case cardTypeForeignIdentityCard: return 6 default: log.Warn("ArgRealnameList : %+v , unknown CardType", a) return -1 } } // DBCountry return country store in db func (a *ArgRealnameList) DBCountry() int { if a.CardType == "" { return -1 } return a.Country } // DBState return state store in db func (a *ArgRealnameList) DBState() int { switch a.State { case RealnameApplyStateAll: return -1 case RealnameApplyStatePending: return 0 case RealnameApplyStatePassed: return 1 case RealnameApplyStateRejective: return 2 case RealnameApplyStateNone: return 3 default: log.Warn("ArgRealnameList : %+v , unknown State", a) return 0 } } // ArgRealnamePendingList is. type ArgRealnamePendingList struct { Channel realnameChannel `form:"channel" validate:"required"` PS int `form:"ps"` PN int `form:"pn"` } // ArgRealnameAuditApply is. type ArgRealnameAuditApply struct { ID int64 `form:"id" validate:"required"` Channel realnameChannel `form:"channel" validate:"required"` Action realnameAction `form:"action" validate:"required"` Reason string `form:"reason"` } // DBChannel return channel store in db func (a *ArgRealnameAuditApply) DBChannel() int { switch a.Channel { case ChannelMain: return 0 case ChannelAlipay: return 1 default: log.Warn("ArgRealnameAuditApply : %+v , unknown Channel", a) return 0 } } // ArgRealnameReasonList is. type ArgRealnameReasonList struct { PS int `form:"ps"` PN int `form:"pn"` } // ArgRealnameSetReason is. type ArgRealnameSetReason struct { Reasons []string `form:"reasons,split"` } // ArgRealnameImage is. type ArgRealnameImage struct { Token string `form:"token" validate:"required"` } // ArgRealnameImagePreview is. type ArgRealnameImagePreview struct { ArgRealnameImage BorderSize uint `form:"border_size"` // 图片最大边长度(缩放后) } // ArgRealnameSearchCard is. type ArgRealnameSearchCard struct { Cards []string `form:"cards,split" validate:"required"` CardType int `form:"card_type"` Country int `form:"card_type"` } // RespRealnameApply is. type RespRealnameApply struct { ID int64 `json:"id"` Channel realnameChannel `json:"channel"` MID int64 `json:"mid"` Nickname string `json:"nickname"` Times int `json:"times"` CardType RealnameCardType `json:"card_type"` Country int16 `json:"country"` Card string `json:"card"` Realname string `json:"realname"` Level int32 `json:"level"` IMGIDs []int64 `json:"-"` IMGs []string `json:"imgs"` State RealnameApplyStatus `json:"state"` OPName string `json:"op_name"` OPTS int64 `json:"op_ts"` OPReason string `json:"op_reason"` CreateTS int64 `json:"create_ts"` } // ParseDBMainApply parse realname_apply from db func (r *RespRealnameApply) ParseDBMainApply(db *DBRealnameApply) { var err error r.ID = db.ID r.Channel = ChannelMain r.MID = db.MID r.CardType = r.convertCardType(db.CardType) r.Country = db.Country if db.CardNum != "" { if r.Card, err = CardDecrypt(db.CardNum); err != nil { log.Error("%+v", err) } } r.IMGIDs = append(r.IMGIDs, db.HandIMG, db.FrontIMG, db.BackIMG) r.Realname = db.Realname r.State = r.ParseStatus(db.Status) r.OPName = db.Operator r.OPTS = db.OperatorTime.Unix() r.OPReason = db.Remark r.CreateTS = db.CTime.Unix() } // ParseDBAlipayApply parse realname_alipay_apply from db func (r *RespRealnameApply) ParseDBAlipayApply(db *DBRealnameAlipayApply) { var err error r.ID = db.ID r.Channel = ChannelAlipay r.MID = db.MID r.CardType = cardTypeIdentityCard // identity_card r.Country = 0 // china if db.Card != "" { if r.Card, err = CardDecrypt(db.Card); err != nil { log.Error("%+v", err) } } r.ParseDBApplyIMG(db.IMG) r.Realname = db.Realname r.State = r.ParseStatus(db.Status) r.OPName = "alipay" if db.Operator != "" { r.OPName = db.Operator } r.OPTS = db.OperatorTime.Unix() r.OPReason = db.Reason r.CreateTS = db.CTime.Unix() } // ParseDBApplyIMG parse apply_img from db func (r *RespRealnameApply) ParseDBApplyIMG(token string) { r.IMGs = append(r.IMGs, imgURL(token)) } // ParseMember parse member info from rpc call func (r *RespRealnameApply) ParseMember(mem *memmdl.Member) { r.Nickname = mem.Name r.Level = mem.LevelInfo.Cur } func imgURL(token string) string { token = strings.TrimPrefix(token, "/idenfiles/") token = strings.TrimSuffix(token, ".txt") return fmt.Sprintf(conf.Conf.Realname.ImageURLTemplate, token) } // ParseStatus parse status stored in db func (r *RespRealnameApply) ParseStatus(status int) (s RealnameApplyStatus) { switch status { case 0: return RealnameApplyStatePending case 1: return RealnameApplyStatePassed case 2: return RealnameApplyStateRejective default: log.Warn("RespRealnameApply parse status err , unknown apply status :%d", status) return RealnameApplyStateNone } } // ConvertCardType convert card_type from db to api func (r *RespRealnameApply) convertCardType(cardType int8) (t RealnameCardType) { switch cardType { case 0: return cardTypeIdentityCard case 1: return cardTypeForeignPassport case 2: return cardTypeHongkongMacaoPermit case 3: return cardTypeTaiwanPermit case 4: return cardTypeChinaPassport case 5: return cardTypeForeignerPermanentResidenceCard case 6: return cardTypeForeignIdentityCard default: log.Warn("RespRealnameApply parse card type err , unknown card type :%d", cardType) return cardTypeIdentityCard } } // DBRealnameInfo is. type DBRealnameInfo struct { ID int64 `gorm:"column:id"` MID int64 `gorm:"column:mid"` Channel uint8 `gorm:"column:channel"` Realname string `gorm:"column:realname"` Country int16 `gorm:"column:country"` CardType int8 `gorm:"column:card_type"` Card string `gorm:"column:card"` CardMD5 string `gorm:"column:card_md5"` Status int `gorm:"column:status"` Reason string `gorm:"column:reason"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // TableName is... func (d *DBRealnameInfo) TableName() string { return "realname_info" } // DBRealnameApply is. type DBRealnameApply struct { ID int64 `gorm:"column:id"` MID int64 `gorm:"column:mid"` Realname string `gorm:"column:realname"` Country int16 `gorm:"column:country"` CardType int8 `gorm:"column:card_type"` CardNum string `gorm:"column:card_num"` CardMD5 string `gorm:"column:card_md5"` HandIMG int64 `gorm:"column:hand_img"` FrontIMG int64 `gorm:"column:front_img"` BackIMG int64 `gorm:"column:back_img"` Status int `gorm:"column:status"` Operator string `gorm:"column:operator"` OperatorID int64 `gorm:"column:operator_id"` OperatorTime time.Time `gorm:"column:operator_time"` Remark string `gorm:"column:remark"` RemarkStatus int8 `gorm:"column:remark_status"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // TableName is... func (d *DBRealnameApply) TableName() string { return "realname_apply" } // DBRealnameAlipayApply is. type DBRealnameAlipayApply struct { ID int64 `gorm:"column:id"` MID int64 `gorm:"column:mid"` Realname string `gorm:"column:realname"` Card string `gorm:"column:card"` IMG string `gorm:"column:img"` Status int `gorm:"column:status"` Reason string `gorm:"column:reason"` Bizno string `gorm:"column:bizno"` Operator string `gorm:"column:operator"` OperatorID int64 `gorm:"column:operator_id"` OperatorTime time.Time `gorm:"column:operator_time"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // TableName is... func (d *DBRealnameAlipayApply) TableName() string { return "realname_alipay_apply" } // IsPassed is... func (d *DBRealnameApply) IsPassed() bool { return d.Status == 1 } // DBRealnameApplyIMG is. type DBRealnameApplyIMG struct { ID int64 `gorm:"column:id"` IMGData string `gorm:"column:img_data"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // TableName ... func (d *DBRealnameApplyIMG) TableName() string { return "realname_apply_img" } // DBRealnameConfig ... type DBRealnameConfig struct { ID int64 `gorm:"column:id"` Key string `gorm:"column:key"` Data string `gorm:"column:data"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // TableName ... func (d *DBRealnameConfig) TableName() string { return "realname_config" } // CardDecrypt is func CardDecrypt(data string) (text string, err error) { var ( dataBytes = []byte(data) decryptedData []byte textBytes []byte size int ) decryptedData = make([]byte, base64.StdEncoding.DecodedLen(len(dataBytes))) if size, err = base64.StdEncoding.Decode(decryptedData, dataBytes); err != nil { err = errors.Wrapf(err, "base decode %s", data) return } if textBytes, err = rsaDecrypt(decryptedData[:size]); err != nil { err = errors.Wrapf(err, "rsa decrypt %s , data : %s", decryptedData, data) return } text = string(textBytes) return } func rsaDecrypt(text []byte) (content []byte, err error) { block, _ := pem.Decode(conf.Conf.Realname.RsaPriv) if block == nil { err = errors.New("private key error") return } var ( privateKey *rsa.PrivateKey ) if privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { err = errors.WithStack(err) return } if content, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, text); err != nil { err = errors.WithStack(err) return } return } // DBRealnameAuditLog is. type DBRealnameAuditLog struct { ID int64 `gorm:"column:id"` MID int64 `gorm:"column:mid"` AdminID int64 `gorm:"column:admin_id"` AdminName string `gorm:"column:admin_name"` Channel uint8 `gorm:"column:channel"` FromState int `gorm:"column:from_state"` ToState int `gorm:"column:to_state"` CTime time.Time `gorm:"column:ctime"` MTime time.Time `gorm:"column:mtime"` } // Tablename is. func (d *DBRealnameAuditLog) Tablename() string { return "realname_audit_log" } // Realname is. type Realname struct { State RealnameApplyStatus `json:"state"` Channel realnameChannel `json:"moral"` Card string `json:"card"` CardType int8 `json:"card_type"` Country int16 `json:"country"` Realname string `json:"realname"` Images []string `json:"images"` } // ParseDBApplyIMG parse apply_img from db func (r *Realname) ParseDBApplyIMG(token string) { r.Images = append(r.Images, imgURL(token)) } // ParseInfo . func (r *Realname) ParseInfo(info *DBRealnameInfo) { switch info.Status { case 0: r.State = RealnameApplyStatePending case 1: r.State = RealnameApplyStatePassed case 2: r.State = RealnameApplyStateRejective default: log.Warn("Realname status err , unknown info status :%d", info.Status) r.State = RealnameApplyStateNone } switch info.Channel { case 0: r.Channel = ChannelMain case 1: r.Channel = ChannelAlipay default: log.Warn("Realname channel err , unknown info channel :%d", info.Channel) r.Channel = ChannelMain } r.Realname = info.Realname r.CardType = info.CardType r.Country = info.Country var err error var maskedCard string if info.Card != "" && r.State == RealnameApplyStatePassed { if r.Card, err = CardDecrypt(info.Card); err != nil { log.Error("%+v", err) } var ( cStrs = strings.Split(r.Card, "") ) if len(cStrs) > 0 { if len(cStrs) == 1 { maskedCard = "*" } else if len(cStrs) > 5 { maskedCard = cStrs[0] + strings.Repeat("*", len(cStrs)-3) + strings.Join(cStrs[len(cStrs)-2:], "") } else { maskedCard = cStrs[0] + strings.Repeat("*", len(cStrs)-1) } } r.Card = maskedCard } } // RealnameExport is. type RealnameExport struct { Mid int64 `json:"mid" gorm:"column:mid"` UserID string `json:"userid" gorm:"column:userid"` Uname string `json:"uname" gorm:"column:uname"` Realname string `json:"realname" gorm:"column:realname"` Tel string `json:"tel" gorm:"column:tel"` CardType int8 `json:"card_type" gorm:"column:card_type"` CardNum string `json:"card_num" gorm:"column:card_num"` } // PassportQueryByMidResult is. type PassportQueryByMidResult struct { Mid int64 `json:"mid"` Name string `json:"name"` Userid string `json:"userid"` Email string `json:"email"` Tel string `json:"tel"` Jointime xtime.Time `json:"jointime"` } var _cardTypeToString = map[int8]string{ 0: "身份证", 1: "护照(境外签发)", 2: "港澳居民来往内地通行证", 3: "台湾居民来往大陆通行证", 4: "护照(中国签发)", 5: "外国人永久居留证", 6: "其他国家或地区身份证", } // CardTypeString is func CardTypeString(cardType int8) string { typeString, ok := _cardTypeToString[cardType] if !ok { return strconv.FormatInt(int64(cardType), 10) } return typeString }