Commit f50bf998 by zhengqiuyun86

初始化

parent 7610d771
package PagePlus
import (
"git.168cad.top/zhengqiuyun/rym-util/a/util"
"git.168cad.top/zhengqiuyun/rym-util/exception"
page2 "git.168cad.top/zhengqiuyun/rym-util/page"
"gorm.io/gorm"
)
func Page(params []page2.Param, pageNum int, pageSize int, m interface{}, data interface{}, orderBy string, db *gorm.DB) *page2.Data {
var page = page2.Data{}
page.PageSize = util.IfInt(pageSize == 0, 10, pageSize)
page.PageNum = util.IfInt(pageNum == 0, 1, pageNum)
tx := db.Session(&gorm.Session{PrepareStmt: true})
countTx := tx.Model(&m).Select("count(1)")
if params != nil {
for _, p := range params {
countTx.Where(p.Column+" "+p.Op+" ?", p.Value)
}
}
resultCount := countTx.Scan(&page.Total)
if resultCount.Error != nil {
exception.ThrowsErr(resultCount.Error)
}
if page.Total > 0 {
dataTx := tx.Model(&m).Offset((page.PageNum - 1) * page.PageSize).Limit(page.PageSize).Order(orderBy)
if params != nil {
for _, p := range params {
dataTx.Where(p.Column+" "+p.Op+" ?", p.Value)
}
}
resultList := dataTx.Find(&data)
if resultList.Error != nil {
exception.ThrowsErr(resultList.Error)
}
page.List = data
}
return &page
}
package exception
import (
"errors"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"reflect"
)
func ThrowsErr(err error) {
if err != nil {
log.Error(err.Error())
panic(err)
}
}
func ThrowsValid(err error, r interface{}) {
if err != nil {
switch err.(type) {
case validator.ValidationErrors:
e := (err).(validator.ValidationErrors)
errMsg := getError(e, r)
panic(errors.New(errMsg))
break
default:
panic(err)
break
}
}
}
// 自定义错误消息
func getError(errs validator.ValidationErrors, r interface{}) string {
s := reflect.TypeOf(r)
for _, fieldError := range errs {
filed, _ := s.FieldByName(fieldError.Field())
// 获取统一错误消息
errText := filed.Tag.Get("msg")
if errText != "" {
return errText
}
fieldName := filed.Tag.Get("json")
if fieldName == "" {
fieldName = fieldError.Field()
}
return fieldName + ":" + fieldError.Tag()
}
return ""
}
type DError struct {
Err string
}
func (e *DError) Error() string {
return e.Err
}
func ThrowsErrS(err string) {
if &err != nil && err != "" {
log.Error(err)
panic(DError{Err: err})
}
}
package catch
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"git.168cad.top/zhengqiuyun/rym-util/getWay"
"github.com/gin-gonic/gin"
"runtime"
"strings"
)
func ExceptionCatch(c *gin.Context) {
err := recover() //获取异常
if err != nil {
switch err.(type) {
case exception.DError:
e := (err).(exception.DError)
getWay.FailAndMsg(c, e.Error())
break
case error:
e := (err).(error)
if strings.Index(e.Error(), "duplicate key") > 0 {
getWay.FailAndMsg(c, "信息重复")
} else {
var buf [1024]byte
n := runtime.Stack(buf[:], true)
fmt.Println(string(buf[:]), n)
getWay.FailAndMsg(c, e.Error())
}
break
}
}
}
package generate
func MysqlAllTables() []Table {
var tables []Table
//查询库中所有表
tablesSql := "\nSELECT\ntable_name AS name,\nTABLE_COMMENT as description\nFROM\ninformation_schema.TABLES\nwhere table_schema=?"
db.GetPgDb().Raw(tablesSql, NameSpace).Scan(&tables)
return tables
}
func MysqlGetTableFiledByTableName(tableName string) []TableField {
var tableFields []TableField
tableInfoSql := "\nSELECT\n" +
"column_name as field_name,\n" +
"data_type as field_type,\n" +
"CHARACTER_MAXIMUM_LENGTH as length,\n" +
"CHARACTER_MAXIMUM_LENGTH as length_var,\n" +
"false as not_null,\n" +
"COLUMN_COMMENT as `comment`,\n" +
"COLUMN_TYPE as column_type\n" +
"FROM\n" +
"information_schema.columns\n" +
"where table_name=?\n" +
"and TABLE_SCHEMA=?\n" +
"order by column_name"
db.GetPgDb().Raw(tableInfoSql, tableName, NameSpace).Scan(&tableFields)
return tableFields
}
package generate
func AllTables() []Table {
var tables []Table
//查询库中所有表
tablesSql := "SELECT a.oid,\n a.relname AS name,\n b.description\n FROM pg_class a\n LEFT OUTER JOIN pg_description b ON b.objsubid=0 AND a.oid = b.objoid\n WHERE a.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname='public')\n AND a.relkind='r'\n ORDER BY a.relname"
db.GetPgDb().Raw(tablesSql).Scan(&tables)
return tables
}
func GetTableFiledByTableName(tableName string) []TableField {
var tableFields []TableField
tableInfoSql := "SELECT a.attname AS field_name,\n t.typname AS field_type,\n a.attlen AS length,\n a.atttypmod AS length_var,\n a.attnotnull AS notnull,\n b.description AS comment\n FROM pg_class c,\n pg_attribute a\n LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,\n pg_type t\n WHERE c.relname = ?\n and a.attnum > 0\n and a.attrelid = c.oid\n and a.atttypid = t.oid\n ORDER BY a.attnum"
db.GetPgDb().Raw(tableInfoSql, tableName).Scan(&tableFields)
return tableFields
}
package getWay
type Error struct {
Code State
}
func ThrowsGetWayErr(code State) {
if &code != nil {
panic(Error{code})
}
}
package getWay
import (
"git.168cad.top/zhengqiuyun/rym-util/exception"
"github.com/gin-gonic/gin"
)
const headerKeyToken = "token"
const headerKeyPlatformCode = "platform"
const headerKeyClientSource = "clientSource"
func getHeader(c *gin.Context, key string) string {
v := c.GetHeader(key)
return v
}
func GetToken(c *gin.Context) string {
return getHeader(c, headerKeyToken)
}
func SetToken(v string, c *gin.Context) {
c.Header(headerKeyToken, v)
}
func GetPlatformCode(c *gin.Context) string {
platformCode := getHeader(c, headerKeyPlatformCode)
if platformCode == "" {
exception.ThrowsErrS("平台错误")
}
return platformCode
}
func GetClientSource(c *gin.Context) string {
platformCode := getHeader(c, headerKeyClientSource)
return platformCode
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/db/redis"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"github.com/gin-gonic/gin"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
)
func GetCurrentUserId(c *gin.Context) (uint32, bool) {
userId, b := c.Get(CurrentUserIdKey)
if b {
transUserId := userId.(uint32)
return transUserId, b
}
return 0, b
}
type UserInfo struct {
Id uint32
Account string
Name string
}
func GetCurrentUser(c *gin.Context) *UserInfo {
var userInfo = UserInfo{}
adminResponse, b := c.Get(CurrentUserKey)
if b {
admin := adminResponse.(Admin)
userInfo.Name = admin.Name
userInfo.Account = admin.LoginAccount
userInfo.Id = admin.Id
}
return &userInfo
}
func GetAdminInfo(token string) Admin {
var adminResponse = AdminResponse{}
resp, err := http.Get(conf.SystemHost + "/admin/current?token=" + token)
if err != nil {
log.Error(err.Error())
return Admin{}
}
defer resp.Body.Close()
adminResponseBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error(err.Error())
return Admin{}
}
err = json.Unmarshal(adminResponseBytes, &adminResponse)
if err != nil {
log.Error(err.Error())
}
return adminResponse.Admin
}
type AdminResponse struct {
code int
msg string
Admin Admin
}
type Admin struct {
Id uint32
Name string
LoginAccount string
}
const requestBodyKey = "requestBody"
func BindRequestBody(c *gin.Context, param interface{}) error {
c.ShouldBindJSON(param)
bytes, err := json.Marshal(param)
c.Set(requestBodyKey, string(bytes))
return err
}
func GetParams(c *gin.Context) string {
rd := ""
params := c.Request.URL.Query().Encode()
if params != "" {
rd += params
}
ad := c.GetString(requestBodyKey)
if ad != "" {
rd += ad
}
return rd
}
func GetServerIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, addr := range addrs {
ipAddr, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipAddr.IP.IsLoopback() {
continue
}
if !ipAddr.IP.IsGlobalUnicast() {
continue
}
return ipAddr.IP.String()
}
return ""
}
func GetClientIP(c *gin.Context) string {
ip := c.ClientIP()
return ip
}
func GetURL(c *gin.Context) string {
url := c.Request.URL.Path
return url
}
func GetMethod(c *gin.Context) string {
method := c.Request.Method
return method
}
func SetStartTime(c *gin.Context) {
c.Set(StartTimeKey, time.Now().UnixNano())
logStart(c)
}
func GetStartTime(c *gin.Context) int64 {
startTime := c.GetInt64(StartTimeKey)
return startTime
}
func ValidRequest(c *gin.Context) {
defer exceptionGetWayCatch(c)
ip := c.ClientIP()
url := c.Request.RequestURI
token := GetToken(c)
if token == "" {
if checkIp(ip) { //如果没有token,看是否是ip白名单
log.Debug(fmt.Sprintf("IP白名单校验通过:%s", ip))
} else {
log.Debug(fmt.Sprintf("IP白名单校验不通过:%s", ip))
if checkUri(url) { //如果不是ip白名单,看是否是url白名单,例如一些第三方的回调
log.Debug(fmt.Sprintf("URL白名单校验通过:%s", url))
} else {
log.Debug(fmt.Sprintf("URL白名单校验不通过:%s", url))
ThrowsGetWayErr(Illegal9)
}
}
} else {
if redis.Exists(token) { //校验token是否有效
currentUser := GetAdminInfo(token)
c.Set(CurrentUserKey, currentUser)
log.Debug(fmt.Sprintf("登陆校验通过:%s,对应用户id: %d", token, currentUser.Id))
} else {
log.Debug(fmt.Sprintf("登陆校验不通过:%s", token))
ThrowsGetWayErr(Expire)
}
}
}
func exceptionGetWayCatch(c *gin.Context) {
err := recover() //获取异常
if err != nil {
switch err.(type) {
case Error:
e := (err).(Error)
FailGetWay(c, e.Code)
break
}
}
}
func checkUri(uri string) bool {
for _, v := range conf.WhiteListUri {
if strings.Index(uri, v) == 0 {
return true
}
}
return false
}
func checkIp(ip string) bool {
for _, v := range conf.WhiteListIp {
if strings.Index(ip, v) == 0 {
return true
}
}
return false
}
func logStart(c *gin.Context) {
log.Info(fmt.Sprintf("开始 %s %s %s %s", GetMethod(c), GetURL(c), GetToken(c), GetClientIP(c)))
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
db "git.168cad.top/zhengqiuyun/rym-util/a/db/mysql"
"git.168cad.top/zhengqiuyun/rym-util/a/db/redis"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/a/log/es"
conf2 "git.168cad.top/zhengqiuyun/rym-util/conf"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type ServerResponse struct {
Code State `json:"code"` //0为成功,其他都是失败
Msg string `json:"msg,omitempty"` //非1000情况下的错误描述
}
type ServerDataResponse struct {
ServerResponse
Data interface{} `json:"data,omitempty"`
}
func response(state State) ServerResponse {
return ServerResponse{Code: state, Msg: state.String()}
}
func FailGetWay(c *gin.Context, state State) {
resp := response(state)
c.JSON(http.StatusBadGateway, resp)
c.Abort()
logEnd(c, resp)
}
func FailAndMsg(c *gin.Context, msg string) {
db.Rollback()
resp := ServerResponse{Code: BusinessError, Msg: msg}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func Success(c *gin.Context) {
db.Commit()
resp := response(OK)
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func SuccessData(c *gin.Context, data interface{}) {
db.Commit()
resp := ServerDataResponse{response(OK), data}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
type WxResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
func WxSuccess(c *gin.Context) {
resp := WxResponse{"SUCCESS", "成功"}
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func AliSuccess(c *gin.Context) {
resp := "success"
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func logEnd(c *gin.Context, data interface{}) {
esSwitch := redis.SwitchOpen(redis.ES日志开关 + conf.ServerName)
startTime := GetStartTime(c)
endTime := time.Now().UnixNano()
var responseStr string
if data != nil {
dataJson, _ := json.Marshal(data)
rs := string(dataJson)
excludeUrl := []string{""}
if esSwitch {
if util.ArrayContains(excludeUrl, GetURL(c)) && len(rs) > conf2.LogResponseLength {
responseStr = rs[0:conf2.LogResponseLength] + "......"
} else {
responseStr = rs
}
} else {
if len(rs) > conf2.LogResponseLength {
responseStr = rs[0:conf2.LogResponseLength] + "......"
} else {
responseStr = rs
}
}
}
token := GetToken(c)
if esSwitch && token != "" {
esLog(c, responseStr)
log.Info(fmt.Sprintf("结束,耗时%d毫秒", (endTime-startTime)/1e6))
} else {
log.Info(fmt.Sprintf("返回数据:%s", responseStr))
log.Info(fmt.Sprintf("结束,耗时%d毫秒 %s %s %s %s %s", (endTime-startTime)/1e6, GetMethod(c), GetURL(c), token, GetClientIP(c), GetParams(c)))
}
}
func esLog(c *gin.Context, response string) {
log := es.ServerLogModel{
ServerName: conf.ServerName,
Env: conf.ENV,
TimeStamp: util.MilSecond(time.Now()),
ThreadNo: fmt.Sprintf("%d", util.GetGID()),
ServerIp: GetServerIP(),
ClientIp: GetClientIP(c),
Token: GetToken(c),
CustomerId: GetCurrentUser(c).Id,
ClientSource: GetClientSource(c),
Url: GetURL(c),
Method: GetMethod(c),
Request: GetParams(c),
Response: response,
DealTimes: util.MilSecond(time.Now()) - GetStartTime(c)/1e6,
}
es.InsertEsLog(log)
}
package getWay
type State int16
// iota 初始化后会自动递增
const (
BusinessError State = 1001
OK State = 1000
Expire State = 1 - iota
Illegal1
Illegal2
Illegal3
Illegal4
Illegal5
Illegal6
Illegal7
Illegal8
Illegal9
)
func (t State) String() string {
switch t {
case BusinessError:
return "business error"
case OK:
return "OK"
case Expire:
return "expire request"
case Illegal1:
return "illegal request(1)"
case Illegal2:
return "illegal request(2)"
case Illegal3:
return "illegal request(3)"
case Illegal4:
return "illegal request(4)"
case Illegal5:
return "illegal request(5)"
case Illegal6:
return "illegal request(6)"
case Illegal7:
return "illegal request(7)"
case Illegal8:
return "illegal request(8)"
case Illegal9:
return "illegal request(9)"
default:
return "unknown"
}
}
package getWay
const CurrentUserKey = "userInfo"
const CurrentUserIdKey = "userID"
const StartTimeKey = "StartTime"
const LoginUri = "/api/v1/app/login"
const LoginExpire = 10 * 24 * 60 * 60
package jeff
func CheckCRC(buf []byte) bool {
var wCrcData uint16 = 0xffff
for _, v := range buf {
wCrcData ^= uint16(v)
for j := 0; j < 8; j++ {
if wCrcData&1 != 0 {
wCrcData >>= 1
wCrcData ^= 0xa001
} else {
wCrcData >>= 1
}
}
}
return wCrcData == 0
}
// GetCRC 获取2个字节的CRC16
func GetCRC(buf []byte, len int) { //传入的切片必须装得下
var wCrcData uint16 = 0xffff
for i := 0; i < len; i++ {
wCrcData ^= uint16(buf[i])
for j := 0; j < 8; j++ {
if wCrcData&1 != 0 {
wCrcData >>= 1
wCrcData ^= 0xa001
} else {
wCrcData >>= 1
}
}
}
buf[len] = byte(wCrcData)
buf[len+1] = byte(wCrcData >> 8)
}
package jeff
import (
"encoding/base64"
"errors"
)
func EncryptBytesToBase64(cleartext []byte, pswd string, iv string) (base64Result []byte) { //看base64库,返回切片更快,本来tcp发送也是切片,不过这里面string也是切片
var pswdIv [16]byte
var pswdSum byte
var i int
cleartextLen := len(cleartext)
var result = make([]byte, cleartextLen+1)
for i = 0; i < 16; i++ {
pswdIv[i] = ((pswd[i] & 0xaa) | (pswd[15-i] & 0x55)) + iv[15-i] + byte(i)
if i%2 == 0 {
pswdSum += pswd[i] + iv[i]
} else {
pswdSum -= pswd[i] - iv[i]
}
}
for i = 0; i < 16; i++ {
if i%2 == 0 {
pswdIv[i] = ^pswdIv[i] + pswdSum
} else {
pswdIv[i] = pswdIv[i] - ^pswdSum
}
}
result[cleartextLen] = ^pswdSum
for i = 0; i < cleartextLen; i++ {
result[cleartextLen] += cleartext[i]
}
for i = 0; i < cleartextLen; i++ {
result[i] = ^((cleartext[i] & 0x72) | (cleartext[cleartextLen-1-i] & 0x8d))
if i%2 == 0 {
result[i] += pswdIv[i%16] - result[cleartextLen]
} else {
result[i] -= pswdIv[i%16] + result[cleartextLen]
}
}
base64Result = make([]byte, base64.StdEncoding.EncodedLen(cleartextLen+1)+2) //多出两个用来装起始结束符
base64.StdEncoding.Encode(base64Result[1:], result)
return
//return base64.StdEncoding.EncodeToString(result)
}
// DecryptBase64ToBytes 解密并转换为bytes
func DecryptBase64ToBytes(ciphertext []byte, pswd string, iv string) ([]byte, error) { //看base64库,传入切片更快,本来tcp接收也是切片,不过这里面string也是切片
var pswdIv [16]byte
var pswdSum byte
var i int
cipherBytes := make([]byte, base64.StdEncoding.DecodedLen(len(ciphertext)))
hexLen, err := base64.StdEncoding.Decode(cipherBytes, ciphertext)
//cipherBytes, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return nil, err
}
clearLen := hexLen - 1
var resultBytes = make([]byte, clearLen)
var resultBytesTemp = make([]byte, clearLen)
for i = 0; i < 16; i++ {
pswdIv[i] = ((pswd[i] & 0xaa) | (pswd[15-i] & 0x55)) + iv[15-i] + byte(i)
if i%2 == 0 {
pswdSum += pswd[i] + iv[i]
} else {
pswdSum -= pswd[i] - iv[i]
}
}
for i = 0; i < 16; i++ {
if i%2 == 0 {
pswdIv[i] = ^pswdIv[i] + pswdSum
} else {
pswdIv[i] = pswdIv[i] - ^pswdSum
}
}
for i = 0; i < clearLen; i++ {
if i%2 == 0 {
resultBytesTemp[i] = ^(cipherBytes[i] - (pswdIv[i%16] - cipherBytes[clearLen]))
} else {
resultBytesTemp[i] = ^(cipherBytes[i] + (pswdIv[i%16] + cipherBytes[clearLen]))
}
}
var sum byte
for i = 0; i < clearLen; i++ {
resultBytes[i] = (resultBytesTemp[i] & 0x72) | (resultBytesTemp[clearLen-1-i] & 0x8d)
sum += resultBytes[i]
}
sum += ^pswdSum
if sum != cipherBytes[clearLen] {
return nil, errors.New("密文校验错误")
}
return resultBytes, nil
}
func EncryptBytesToBase64URL(cleartext []byte, pswd string) string {
var i int
cleartextLen := len(cleartext)
var result = make([]byte, cleartextLen+1)
result[cleartextLen] = 0x11
for i = 0; i < cleartextLen; i++ {
if i%2 == 0 {
result[cleartextLen] -= cleartext[i] | 0x23
} else {
result[cleartextLen] += cleartext[i] & 0x36
}
result[cleartextLen] += ^((cleartext[i] >> 3) | (cleartext[i] << 5))
}
for i = 0; i < cleartextLen; i++ {
result[i] = ^((cleartext[i] & 0x72) | (cleartext[cleartextLen-1-i] & 0x8d))
if i%2 == 0 {
result[i] += pswd[i%16] - result[cleartextLen]
} else {
result[i] -= pswd[i%16] + result[cleartextLen]
}
}
return base64.URLEncoding.EncodeToString(result)
}
func DecryptBase64URLToBytes(ciphertext string, pswd string) ([]byte, error) { //
var i int
hex, err := base64.URLEncoding.DecodeString(ciphertext)
if err != nil {
return nil, err
}
clearLen := len(hex) - 1
var resultBytes = make([]byte, clearLen)
var resultBytesTemp = make([]byte, clearLen)
for i = 0; i < clearLen; i++ {
if i%2 == 0 {
resultBytesTemp[i] = ^(hex[i] - (pswd[i%16] - hex[clearLen]))
} else {
resultBytesTemp[i] = ^(hex[i] + (pswd[i%16] + hex[clearLen]))
}
}
var sum byte
for i = 0; i < clearLen; i++ {
resultBytes[i] = (resultBytesTemp[i] & 0x72) | (resultBytesTemp[clearLen-1-i] & 0x8d)
//sum += resultBytes[i]
if i%2 == 0 {
sum -= resultBytes[i] | 0x23
} else {
sum += resultBytes[i] & 0x36
}
sum += ^((resultBytes[i] >> 3) | (resultBytes[i] << 5))
}
sum += 0x11
if sum != hex[clearLen] {
return nil, errors.New("密文校验错误")
}
return resultBytes, nil
}
package jeff
//import (
// "git.168cad.top/zhengqiuyun/rym-util/a/getWay"
// cache "git.168cad.top/zhengqiuyun/rym-util/app/cache/customer"
// "math/rand"
// "time"
//)
//
//const jeffWTKey = "ekkidlsedksldkkk"
//
//const tokenClearLen = 20
//const tokenLen = 28
//
//type tokenResult struct {
// CreatTime int64 //token创建时间
// UserID uint32 //
// ExpireTime uint32
// UserType uint8 // 1微信家长 2后台用户 3硬件设备 4服务器请求 其余预留
// UserLevel uint8 // 用户等级
// CheckResult getWay.State
//}
//
//func CreateAppToken(creatTime int64, userID, expireTime uint32) string {
// cache.SetAppToken(userID)
// return createToken(creatTime, userID, expireTime, 1, 0)
//}
//
//func CreateServerToken(creatTime int64, expireTime uint32) string {
// return createToken(creatTime, 1, expireTime, 4, 0)
//}
//
//// CreateToken 生成token,duration到期时间,秒的时间戳
//func createToken(creatTime int64, userID, expireTime uint32, userType, userLevel uint8) string {
// var clear = make([]byte, tokenClearLen) //7字节创建时间 4字节结束时间 4字节有效时长 2字节CRC 3字节随机数预留
// r := rand.New(rand.NewSource(time.Now().UnixNano()))
// random := byte(r.Intn(256))
//
// clear[0] = ^byte(userID>>24) - random
// clear[1] = byte(expireTime>>16) - random
// clear[2] = byte(userID>>16) + random + 166
// clear[3] = ^byte(creatTime>>24) - random
// clear[4] = byte(creatTime>>48) - random + 23
// clear[5] = ^byte(expireTime >> 8)
// clear[6] = byte(creatTime>>32) + random + 66
// clear[7] = byte(expireTime>>24) + random + 99
// clear[8] = byte(creatTime>>16) + random - 88
// clear[9] = ^byte(userID)
// clear[10] = byte(creatTime) - 69
// clear[11] = byte(expireTime) + random + 27
// clear[12] = byte(userID>>8) - random - 33
// clear[13] = ^byte(creatTime>>40) - random - 28
// clear[14] = byte(creatTime>>8) - random - 69
// clear[15] = ^random + 0x5a
// clear[16] = userType + (userLevel << 4) - random
// clear[17] = 0x1a + random
// GetCRC(clear, 18)
// clear[18] = ^(clear[18] + random - 15)
// clear[19] = ^clear[19] - random
//
// return EncryptBytesToBase64URL(clear, jeffWTKey)
//}
//
//func decryptAndCheckToken(token string) (clearStruct tokenResult) {
// if len(token) != tokenLen {
// getWay.ThrowsGetWayErr(getWay.Illegal1)
// return
// }
// clear, err := DecryptBase64URLToBytes(token, jeffWTKey)
// if err != nil {
// getWay.ThrowsGetWayErr(getWay.Illegal2)
// return
// }
// if len(clear) != tokenClearLen {
// getWay.ThrowsGetWayErr(getWay.Illegal3)
// return
// }
// random := clear[17] - 0x1a
// if clear[15] != ^random+0x5a {
// getWay.ThrowsGetWayErr(getWay.Illegal4)
// return
// }
// clear[18] = ^clear[18] - random + 15
// clear[19] = ^(clear[19] + random)
// if CheckCRC(clear) == false {
// getWay.ThrowsGetWayErr(getWay.Illegal5)
// return
// }
// clearStruct.ExpireTime = (uint32(clear[11] - 27 - random)) +
// (uint32(^clear[5]) << 8) +
// (uint32(clear[1]+random) << 16) +
// (uint32(clear[7]-random-99) << 24)
// if uint32(time.Now().Unix()) > clearStruct.ExpireTime { // 到期时间已经过了
// getWay.ThrowsGetWayErr(getWay.Illegal6)
// return
// }
// clearStruct.CreatTime = int64(clear[10]+69) +
// (int64(clear[14]+69+random) << 8) +
// (int64(clear[8]+88-random) << 16) +
// (int64(^(clear[3] + random)) << 24) +
// (int64(clear[6]-66-random) << 32) +
// (int64(^(clear[13] + 28 + random)) << 40) +
// (int64(clear[4]-23+random) << 48)
//
// if time.Now().UnixMicro() < clearStruct.CreatTime { // 创建时间居然大于当前时间
// getWay.ThrowsGetWayErr(getWay.Illegal7)
// return
// }
// clearStruct.UserID = uint32(^clear[9]) +
// (uint32(clear[12]+33+random) << 8) +
// (uint32(clear[2]-166-random) << 16) +
// (uint32(^(clear[0] + random)) << 24)
//
// clearStruct.UserType = clear[16] + random
// clearStruct.UserType = clearStruct.UserType & 0xf
//
// clearStruct.CheckResult = getWay.OK
// if clearStruct.UserType != 1 && clearStruct.UserType != 2 {
// getWay.ThrowsGetWayErr(getWay.Illegal8)
// }
// return
//}
//
//func CheckTokenExit(clearStruct *tokenResult) {
// v := cache.GetAppToken(clearStruct.UserID)
// if !v {
// getWay.ThrowsGetWayErr(getWay.Expire)
// return
// }
//}
module git.168cad.top/zhengqiuyun/rym-util module git.168cad.top/zhengqiuyun/rym-util
go 1.16 go 1.16
require (
)
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/smartwalle/crypto4go v1.0.3
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)
package alipay
import "fmt"
const (
kSandboxURL = "https://openapi.alipaydev.com/gateway.do"
kProductionURL = "https://openapi.alipay.com/gateway.do"
kProductionMAPIURL = "https://mapi.alipay.com/gateway.do"
kFormat = "JSON"
kCharset = "utf-8"
kVersion = "1.0"
kSignTypeRSA2 = "RSA2"
kContentType = "application/x-www-form-urlencoded;charset=utf-8"
kTimeFormat = "2006-01-02 15:04:05"
)
const (
kResponseSuffix = "_response"
kErrorResponse = "error_response"
kSignNodeName = "sign"
kSignTypeNodeName = "sign_type"
kCertSNNodeName = "alipay_cert_sn"
kCertificateEnd = "-----END CERTIFICATE-----"
)
// Code 支付宝接口响应 code https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105806&docType=1
type Code string
func (c Code) IsSuccess() bool {
return c == CodeSuccess
}
const (
CodeSuccess Code = "10000" // 接口调用成功
CodeUnknowError Code = "20000" // 服务不可用
CodeInvalidAuthToken Code = "20001" // 授权权限不足
CodeMissingParam Code = "40001" // 缺少必选参数
CodeInvalidParam Code = "40002" // 非法的参数
CodeBusinessFailed Code = "40004" // 业务处理失败
CodePermissionDenied Code = "40006" // 权限不足
)
type Param interface {
// 用于提供访问的 method
APIName() string
// 返回参数列表
Params() map[string]string
}
type ErrorRsp struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
}
func (this *ErrorRsp) Error() string {
return fmt.Sprintf("%s - %s", this.Code, this.SubMsg)
}
type CertDownload struct {
AppAuthToken string `json:"-"` // 可选
AliPayCertSN string `json:"alipay_cert_sn"` // 支付宝公钥证书序列号
}
func (this CertDownload) APIName() string {
return "alipay.open.app.alipaycert.download"
}
func (this CertDownload) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
return m
}
type CertDownloadRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
AliPayCertContent string `json:"alipay_cert_content"`
} `json:"alipay_open_app_alipaycert_download_response"`
Sign string `json:"sign"`
}
package alipay
import (
"crypto"
"net/url"
"strings"
)
// PublicAppAuthorize 用户信息授权接口(网站支付宝登录快速接入) https://docs.open.alipay.com/289/105656#s3 (https://docs.open.alipay.com/263/105809)
func (this *Client) PublicAppAuthorize(scopes []string, redirectURI, state string) (result *url.URL, err error) {
var domain = kSandboxPublicAppAuthorize
if this.isProduction {
domain = kProductionPublicAppAuthorize
}
var p = url.Values{}
p.Set("app_id", this.appId)
p.Set("scope", strings.Join(scopes, ","))
p.Set("redirect_uri", redirectURI)
if state != "" {
p.Set("state", state)
}
result, err = url.Parse(domain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, nil
}
// SystemOauthToken 换取授权访问令牌接口 https://docs.open.alipay.com/api_9/alipay.system.oauth.token
func (this *Client) SystemOauthToken(param SystemOauthToken) (result *SystemOauthTokenRsp, err error) {
err = this.doRequest("POST", param, &result)
if result != nil {
if result.Error != nil {
result.Content.Code = Code(result.Error.Code)
result.Content.Msg = result.Error.Msg
result.Content.SubCode = result.Error.SubCode
result.Content.SubMsg = result.Error.SubMsg
} else {
result.Content.Code = CodeSuccess
}
}
return result, err
}
// UserInfoShare 支付宝会员授权信息查询接口 https://docs.open.alipay.com/api_2/alipay.user.info.share
func (this *Client) UserInfoShare(param UserInfoShare) (result *UserInfoShareRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// AppToAppAuth 第三方应用授权接口 https://docs.open.alipay.com/20160728150111277227/intro
func (this *Client) AppToAppAuth(redirectURI string) (result *url.URL, err error) {
var domain = kSandboxAppToAppAuth
if this.isProduction {
domain = kProductionAppToAppAuth
}
var p = url.Values{}
p.Set("app_id", this.appId)
p.Set("redirect_uri", redirectURI)
result, err = url.Parse(domain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, nil
}
// OpenAuthTokenApp 换取应用授权令牌接口 https://docs.open.alipay.com/api_9/alipay.open.auth.token.app
func (this *Client) OpenAuthTokenApp(param OpenAuthTokenApp) (result *OpenAuthTokenAppRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// AccountAuth 支付宝登录时, 帮客户端做参数签名, 返回授权请求信息字串接口 https://docs.open.alipay.com/218/105327
func (this *Client) AccountAuth(param AccountAuth) (result string, err error) {
var p = url.Values{}
p.Add("app_id", this.appId)
p.Add("method", param.APIName())
var ps = param.Params()
if ps != nil {
for key, value := range ps {
p.Add(key, value)
}
}
p.Add("sign_type", kSignTypeRSA2)
sign, err := signWithPKCS1v15(p, this.appPrivateKey, crypto.SHA256)
if err != nil {
return "", err
}
p.Add("sign", sign)
return p.Encode(), err
}
package alipay
const (
kProductionPublicAppAuthorize = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm"
kSandboxPublicAppAuthorize = "https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm"
)
const (
kProductionAppToAppAuth = "https://openauth.alipay.com/oauth2/appToAppAuth.htm"
kSandboxAppToAppAuth = "https://openauth.alipaydev.com/oauth2/appToAppAuth.htm"
)
// SystemOauthToken 换取授权访问令牌接口请求参数 https://docs.open.alipay.com/api_9/alipay.system.oauth.token
type SystemOauthToken struct {
AppAuthToken string `json:"-"` // 可选
GrantType string `json:"-"` // 值为 authorization_code 时,代表用code换取;值为refresh_token时,代表用refresh_token换取
Code string `json:"-"`
RefreshToken string `json:"-"`
}
func (this SystemOauthToken) APIName() string {
return "alipay.system.oauth.token"
}
func (this SystemOauthToken) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["grant_type"] = this.GrantType
if this.Code != "" {
m["code"] = this.Code
}
if this.RefreshToken != "" {
m["refresh_token"] = this.RefreshToken
}
return m
}
// SystemOauthTokenRsp 换取授权访问令牌接口请求参数
type SystemOauthTokenRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
UserId string `json:"user_id"`
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
ReExpiresIn int64 `json:"re_expires_in"`
} `json:"alipay_system_oauth_token_response"`
Error *struct {
Code string `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
} `json:"error_response"` // 不要访问此结构体
Sign string `json:"sign"`
}
// UserInfoShare 支付宝会员授权信息查询接口请求参数 https://docs.open.alipay.com/api_2/alipay.user.info.share
type UserInfoShare struct {
AppAuthToken string `json:"-"` // 可选
AuthToken string `json:"-"` // 是
}
func (this UserInfoShare) APIName() string {
return "alipay.user.info.share"
}
func (this UserInfoShare) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["auth_token"] = this.AuthToken
return m
}
// UserInfoShareRsp 支付宝会员授权信息查询接口响应参数
type UserInfoShareRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
AuthNo string `json:"auth_no"`
UserId string `json:"user_id"`
Avatar string `json:"avatar"`
Province string `json:"province"`
City string `json:"city"`
NickName string `json:"nick_name"`
IsStudentCertified string `json:"is_student_certified"`
UserType string `json:"user_type"`
UserStatus string `json:"user_status"`
IsCertified string `json:"is_certified"`
Gender string `json:"gender"`
} `json:"alipay_user_info_share_response"`
Sign string `json:"sign"`
}
// OpenAuthTokenApp 换取应用授权令牌请求参数 https://docs.open.alipay.com/api_9/alipay.open.auth.token.app
type OpenAuthTokenApp struct {
GrantType string `json:"grant_type"` // 值为 authorization_code 时,代表用code换取;值为refresh_token时,代表用refresh_token换取
Code string `json:"code"`
RefreshToken string `json:"refresh_token"`
}
func (this OpenAuthTokenApp) APIName() string {
return "alipay.open.auth.token.app"
}
func (this OpenAuthTokenApp) Params() map[string]string {
var m = make(map[string]string)
m["grant_type"] = this.GrantType
if this.Code != "" {
m["code"] = this.Code
}
if this.RefreshToken != "" {
m["refresh_token"] = this.RefreshToken
}
return m
}
// OpenAuthTokenAppRsp 换取应用授权令牌响应参数 新版返回值 参见 https://opendocs.alipay.com/open/20160728150111277227/intro
type OpenAuthTokenAppRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode Code `json:"sub_code"`
SubMsg string `json:"sub_msg"`
Tokens []*OpenAuthToken `json:"tokens"`
} `json:"alipay_open_auth_token_app_response"`
Sign string `json:"sign"`
}
type OpenAuthToken struct {
AppAuthToken string `json:"app_auth_token"` // 授权令牌信息
AppRefreshToken string `json:"app_refresh_token"` // 令牌信息
AuthAppId string `json:"auth_app_id"` // 授权方应用id
ExpiresIn int64 `json:"expires_in"` // 令牌有效期
ReExpiresIn int64 `json:"re_expires_in"` // 有效期
UserId string `json:"user_id"` // 支付宝用户标识
}
// AccountAuth 支付宝登录时, 帮客户端做参数签名, 返回授权请求信息字串接口请求参数 https://docs.open.alipay.com/218/105327/
type AccountAuth struct {
Pid string `json:"pid"`
TargetId string `json:"target_id"`
AuthType string `json:"auth_type"`
}
func (this AccountAuth) APIName() string {
return "alipay.open.auth.sdk.code.get"
}
func (this AccountAuth) Params() map[string]string {
var m = make(map[string]string)
m["apiname"] = "com.alipay.account.auth"
m["app_name"] = "mc"
m["biz_type"] = "openservice"
m["pid"] = this.Pid
m["product_id"] = "APP_FAST_LOGIN"
m["scope"] = "kuaijie"
m["target_id"] = this.TargetId
m["auth_type"] = this.AuthType
return m
}
package alipay
import (
"errors"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
var (
kSuccess = []byte("success")
)
func NewRequest(method, url string, params url.Values) (*http.Request, error) {
var m = strings.ToUpper(method)
var body io.Reader
if m == "GET" || m == "HEAD" {
if len(params) > 0 {
if strings.Contains(url, "?") {
url = url + "&" + params.Encode()
} else {
url = url + "?" + params.Encode()
}
}
} else {
body = strings.NewReader(params.Encode())
}
return http.NewRequest(m, url, body)
}
func (this *Client) NotifyVerify(partnerId, notifyId string) bool {
var param = url.Values{}
param.Add("service", "notify_verify")
param.Add("partner", partnerId)
param.Add("notify_id", notifyId)
req, err := NewRequest("GET", this.notifyVerifyDomain, param)
if err != nil {
return false
}
rep, err := this.Client.Do(req)
if err != nil {
return false
}
defer rep.Body.Close()
data, err := ioutil.ReadAll(rep.Body)
if err != nil {
return false
}
if string(data) == "true" {
return true
}
return false
}
func (this *Client) GetTradeNotification(req *http.Request) (noti *TradeNotification, err error) {
if req == nil {
return nil, errors.New("request 参数不能为空")
}
if err = req.ParseForm(); err != nil {
return nil, err
}
noti = &TradeNotification{}
noti.AppId = req.FormValue("app_id")
noti.AuthAppId = req.FormValue("auth_app_id")
noti.NotifyId = req.FormValue("notify_id")
noti.NotifyType = req.FormValue("notify_type")
noti.NotifyTime = req.FormValue("notify_time")
noti.TradeNo = req.FormValue("trade_no")
noti.TradeStatus = TradeStatus(req.FormValue("trade_status"))
noti.TotalAmount = req.FormValue("total_amount")
noti.ReceiptAmount = req.FormValue("receipt_amount")
noti.InvoiceAmount = req.FormValue("invoice_amount")
noti.BuyerPayAmount = req.FormValue("buyer_pay_amount")
noti.SellerId = req.FormValue("seller_id")
noti.SellerEmail = req.FormValue("seller_email")
noti.BuyerId = req.FormValue("buyer_id")
noti.BuyerLogonId = req.FormValue("buyer_logon_id")
noti.FundBillList = req.FormValue("fund_bill_list")
noti.Charset = req.FormValue("charset")
noti.PointAmount = req.FormValue("point_amount")
noti.OutTradeNo = req.FormValue("out_trade_no")
noti.OutBizNo = req.FormValue("out_biz_no")
noti.GmtCreate = req.FormValue("gmt_create")
noti.GmtPayment = req.FormValue("gmt_payment")
noti.GmtRefund = req.FormValue("gmt_refund")
noti.GmtClose = req.FormValue("gmt_close")
noti.Subject = req.FormValue("subject")
noti.Body = req.FormValue("body")
noti.RefundFee = req.FormValue("refund_fee")
noti.Version = req.FormValue("version")
noti.SignType = req.FormValue("sign_type")
noti.Sign = req.FormValue("sign")
noti.PassbackParams = req.FormValue("passback_params")
noti.VoucherDetailList = req.FormValue("voucher_detail_list")
noti.AgreementNo = req.FormValue("agreement_no")
noti.ExternalAgreementNo = req.FormValue("external_agreement_no")
//if len(noti.NotifyId) == 0 {
// return nil, errors.New("不是有效的 Notify")
//}
ok, err := this.VerifySign(req.Form)
if ok == false {
return nil, err
}
return noti, err
}
func (this *Client) AckNotification(w http.ResponseWriter) {
AckNotification(w)
}
func AckNotification(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
w.Write(kSuccess)
}
package alipay
const (
NotifyTypeTradeStatusSync = "trade_status_sync"
)
// TradeNotification 通知响应参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.8AmJwg&treeId=203&articleId=105286&docType=1
type TradeNotification struct {
AuthAppId string `json:"auth_app_id"` // App Id
NotifyTime string `json:"notify_time"` // 通知时间
NotifyType string `json:"notify_type"` // 通知类型
NotifyId string `json:"notify_id"` // 通知校验ID
AppId string `json:"app_id"` // 开发者的app_id
Charset string `json:"charset"` // 编码格式
Version string `json:"version"` // 接口版本
SignType string `json:"sign_type"` // 签名类型
Sign string `json:"sign"` // 签名
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商户订单号
OutBizNo string `json:"out_biz_no"` // 商户业务号
BuyerId string `json:"buyer_id"` // 买家支付宝用户号
BuyerLogonId string `json:"buyer_logon_id"` // 买家支付宝账号
SellerId string `json:"seller_id"` // 卖家支付宝用户号
SellerEmail string `json:"seller_email"` // 卖家支付宝账号
TradeStatus TradeStatus `json:"trade_status"` // 交易状态
TotalAmount string `json:"total_amount"` // 订单金额
ReceiptAmount string `json:"receipt_amount"` // 实收金额
InvoiceAmount string `json:"invoice_amount"` // 开票金额
BuyerPayAmount string `json:"buyer_pay_amount"` // 付款金额
PointAmount string `json:"point_amount"` // 集分宝金额
RefundFee string `json:"refund_fee"` // 总退款金额
Subject string `json:"subject"` // 商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来。
Body string `json:"body"` // 商品描述
GmtCreate string `json:"gmt_create"` // 交易创建时间
GmtPayment string `json:"gmt_payment"` // 交易付款时间
GmtRefund string `json:"gmt_refund"` // 交易退款时间
GmtClose string `json:"gmt_close"` // 交易结束时间
FundBillList string `json:"fund_bill_list"` // 支付金额信息
PassbackParams string `json:"passback_params"` // 回传参数
VoucherDetailList string `json:"voucher_detail_list"` // 优惠券信息
AgreementNo string `json:"agreement_no"` //支付宝签约号
ExternalAgreementNo string `json:"external_agreement_no"` // 商户自定义签约号
}
package alipay
import (
"net/url"
)
// TradePagePay 统一收单下单并支付页面接口 https://docs.open.alipay.com/api_1/alipay.trade.page.pay
func (this *Client) TradePagePay(param TradePagePay) (result *url.URL, err error) {
p, err := this.URLValues(param)
if err != nil {
return nil, err
}
result, err = url.Parse(this.apiDomain + "?" + p.Encode())
if err != nil {
return nil, err
}
return result, err
}
// TradeAppPay App支付接口 https://docs.open.alipay.com/api_1/alipay.trade.app.pay
func (this *Client) TradeAppPay(param TradeAppPay) (result string, err error) {
p, err := this.URLValues(param)
if err != nil {
return "", err
}
return p.Encode(), err
}
// TradeFastPayRefundQuery 统一收单交易退款查询接口 https://docs.open.alipay.com/api_1/alipay.trade.fastpay.refund.query
func (this *Client) TradeFastPayRefundQuery(param TradeFastPayRefundQuery) (result *TradeFastPayRefundQueryRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeOrderSettle 统一收单交易结算接口 https://docs.open.alipay.com/api_1/alipay.trade.order.settle
func (this *Client) TradeOrderSettle(param TradeOrderSettle) (result *TradeOrderSettleRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeClose 统一收单交易关闭接口 https://docs.open.alipay.com/api_1/alipay.trade.close/
func (this *Client) TradeClose(param TradeClose) (result *TradeCloseRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeCancel 统一收单交易撤销接口 https://docs.open.alipay.com/api_1/alipay.trade.cancel/
func (this *Client) TradeCancel(param TradeCancel) (result *TradeCancelRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeRefund 统一收单交易退款接口 https://docs.open.alipay.com/api_1/alipay.trade.refund/
func (this *Client) TradeRefund(param TradeRefund) (result *TradeRefundRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradePreCreate 统一收单线下交易预创建接口 https://docs.open.alipay.com/api_1/alipay.trade.precreate/
func (this *Client) TradePreCreate(param TradePreCreate) (result *TradePreCreateRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeQuery 统一收单线下交易查询接口 https://docs.open.alipay.com/api_1/alipay.trade.query/
func (this *Client) TradeQuery(param TradeQuery) (result *TradeQueryRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeCreate 统一收单交易创建接口 https://docs.open.alipay.com/api_1/alipay.trade.create/
func (this *Client) TradeCreate(param TradeCreate) (result *TradeCreateRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradePay 统一收单交易支付接口 https://docs.open.alipay.com/api_1/alipay.trade.pay/
func (this *Client) TradePay(param TradePay) (result *TradePayRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeOrderInfoSync 支付宝订单信息同步接口 https://docs.open.alipay.com/api_1/alipay.trade.orderinfo.sync/
func (this *Client) TradeOrderInfoSync(param TradeOrderInfoSync) (result *TradeOrderInfoSyncRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeRefundAsync 统一收单交易退款(异步)接口 https://opendocs.alipay.com/pre-apis/api_pre/alipay.trade.refund.apply
func (this *Client) TradeRefundAsync(param TradeRefundAsync) (result *TradeRefundAsyncRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
// TradeSettleConfirm 统一收单确认结算接口请求参数 https://opendocs.alipay.com/open/028xqy
func (this *Client) TradeSettleConfirm(param TradeSettleConfirm) (result *TradeSettleConfirmRsp, err error) {
err = this.doRequest("POST", param, &result)
return result, err
}
package alipay
// TradeRefundAsync 统一收单交易退款接口(异步)请求参数 https://opendocs.alipay.com/pre-apis/api_pre/alipay.trade.refund.apply
type TradeRefundAsync struct {
AppAuthToken string `json:"-"` // 可选
NotifyURL string `json:"-"` // 可选
OutTradeNo string `json:"out_trade_no,omitempty"` // 与 TradeNo 二选一
TradeNo string `json:"trade_no,omitempty"` // 与 OutTradeNo 二选一
RefundAmount string `json:"refund_amount"` // 必须 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数
RefundReason string `json:"refund_reason"` // 可选 退款的原因说明
OutRequestNo string `json:"out_request_no"` // 必须 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。
OperatorId string `json:"operator_id"` // 可选 商户的操作员编号
StoreId string `json:"store_id"` // 可选 商户的门店编号
TerminalId string `json:"terminal_id"` // 可选 商户的终端编号
}
func (this TradeRefundAsync) APIName() string {
return "alipay.trade.refund.apply"
}
func (this TradeRefundAsync) Params() map[string]string {
var m = make(map[string]string)
m["app_auth_token"] = this.AppAuthToken
m["notify_url"] = this.NotifyURL
return m
}
// TradeRefundAsyncRsp 统一收单交易退款接口(异步)响应参数
type TradeRefundAsyncRsp struct {
Content struct {
Code Code `json:"code"`
Msg string `json:"msg"`
SubCode string `json:"sub_code"`
SubMsg string `json:"sub_msg"`
TradeNo string `json:"trade_no"` // 支付宝交易号
OutTradeNo string `json:"out_trade_no"` // 商户订单号
OutRequestNo string `json:"out_request_no"` // 本笔退款对应的退款请求号
RefundAmount string `json:"refund_amount"` // 本次退款请求,对应的退款金额
RefundStatus string `json:"refund_status"` // REFUND_PROCESSING 退款处理中;REFUND_SUCCESS 退款处理成功;REFUND_FAIL 退款失败
} `json:"alipay_trade_refund_apply_response"`
Sign string `json:"sign"`
}
func (this *TradeRefundAsyncRsp) IsSuccess() bool {
return this.Content.Code == CodeSuccess
}
package lib_allinpay
import (
"crypto/aes"
"crypto/sha1"
"encoding/hex"
"errors"
"strings"
)
func AesEncryptECB(orgDataStr, keyStr string) (string, error) {
src := []byte(orgDataStr)
key := []byte(keyStr)
key, err := AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return "", err
}
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return strings.ToUpper(hex.EncodeToString(encrypted)), nil
}
func AesDecryptECB(encryptedStr, keyStr string) (string, error) {
encrypted, err := hex.DecodeString(strings.ToLower(encryptedStr))
if err != nil {
return "", err
}
key := []byte(keyStr)
key, err = AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return "", err
}
cipher, _ := aes.NewCipher(generateKey(key))
decrypted := make([]byte, len(encrypted))
//
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return string(decrypted[:trim]), nil
}
func AesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
hashs := Sha1(Sha1(keyBytes))
maxLen := len(hashs)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("invalid length!")
}
return hashs[0:realLen], nil
}
func Sha1(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
package lib_allinpay
import (
"crypto"
"crypto/md5"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/a/conf"
"git.168cad.top/zhengqiuyun/rym-util/a/log"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
type Client struct {
httpClient *http.Client
privateKey *rsa.PrivateKey
tlPublicKey *rsa.PublicKey
}
func New(privateKeyPath, pwd, tlPublicKeyPath string) (*Client, error) {
var client = Client{}
privateKey, err := getPrivateKey(privateKeyPath, pwd)
if err != nil {
return nil, err
}
client.privateKey = privateKey
publicKey, err := loadPublicKeyWithPath(tlPublicKeyPath)
if err != nil {
return nil, err
}
client.tlPublicKey = publicKey
client.httpClient = http.DefaultClient
return &client, nil
}
func (c *Client) doRequest(method string, param Param, result interface{}) (err error) {
var buf io.Reader
requestStr := ""
if param != nil {
p, err := c.URLValues(param)
if err != nil {
return err
}
requestStr = p.Encode()
buf = strings.NewReader(requestStr)
}
log.Debug(fmt.Sprintf("请求参数:%s", requestStr))
req, err := http.NewRequest(method, conf.AllinpayUrl, buf)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
resp, err := c.httpClient.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
log.Debug(fmt.Sprintf("请求结果:%s", string(data)))
ok, err := verifyData(data, c.tlPublicKey)
if err != nil {
return err
}
if !ok {
exception.ThrowsErrS("请求结果校验错误,请检查公钥配置")
}
err = json.Unmarshal(data, result)
if err != nil {
return err
}
return err
}
func verifyData(data []byte, key *rsa.PublicKey) (ok bool, err error) {
sign := ""
dataMap := make(map[string]interface{})
err = json.Unmarshal(data, &dataMap)
var sortKeys = util.SortKeys(dataMap)
signDataMap := make(map[string]interface{})
for _, k := range sortKeys {
if k == "sign" {
sign = dataMap[k].(string)
} else {
signDataMap[k] = dataMap[k]
}
}
signDataByte, _ := json.Marshal(signDataMap)
md5Str := md5B(signDataByte)
signBytes, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return false, err
}
if err = RSAVerifyWithKey([]byte(md5Str), signBytes, key, crypto.SHA256); err != nil {
return false, err
}
return true, nil
}
func (c *Client) URLValues(param Param) (value url.Values, err error) {
var p = url.Values{}
p.Add("appId", conf.AllinpayAppId)
p.Add("method", param.apiName())
p.Add("format", "JSON")
p.Add("charset", "utf-8")
p.Add("timestamp", util.FormatDateTime(time.Now()))
p.Add("version", "1.0")
bytes, err := json.Marshal(param)
if err != nil {
return nil, err
}
p.Add("bizContent", string(bytes))
sign, err := signWithPKCS1v15(p, c.privateKey, crypto.SHA256)
if err != nil {
return nil, err
}
p.Add("sign", sign)
p.Add("signType", "SHA256WithRSA")
return p, nil
}
func signWithPKCS1v15(param url.Values, privateKey *rsa.PrivateKey, hash crypto.Hash) (s string, err error) {
if param == nil {
param = make(url.Values, 0)
}
var pList = make([]string, 0, 0)
for key := range param {
var value = strings.TrimSpace(param.Get(key))
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
log.Debug(fmt.Sprintf("签名数据:%s", src))
md5Str := md5S(src)
sig, err := RSASignWithKey([]byte(md5Str), privateKey, hash)
if err != nil {
return "", err
}
s = base64.StdEncoding.EncodeToString(sig)
return s, nil
}
func md5B(src []byte) string {
h := md5.New()
h.Write(src)
bb := h.Sum(nil)
sEnc := base64.StdEncoding.EncodeToString(bb)
return sEnc
}
func md5S(src string) string {
return md5B([]byte(src))
}
func (c *Client) GetTradeNotification(data map[string]string, sign string) (result PayNotifyData, err error) {
err = c.getDefaultNotification(data, sign, &result)
return result, err
}
func (c *Client) getDefaultNotification(data map[string]string, sign string, result interface{}) error {
var pList = make([]string, 0, 0)
for k, v := range data {
pList = append(pList, k+"="+v)
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
log.Debug(fmt.Sprintf("签名数据:%s", src))
md5Str := md5B([]byte(src))
signBytes, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return err
}
if err = RSAVerifyWithKey([]byte(md5Str), signBytes, c.tlPublicKey, crypto.SHA256); err != nil {
return err
}
err = json.Unmarshal([]byte(data["bizContent"]), result)
if err != nil {
return err
}
return err
}
package lib_allinpay
const (
CodeSuccess = "10000"
)
const (
SubCodeSuccess = "OK"
)
type Param interface {
// APIName 用于提供访问的 method
apiName() string
}
type OpenResponse struct {
Code string
Msg string
SubCode string
SubMsg string
Sign string
TraceId string
}
type DefaultOpenResponse struct {
OpenResponse
Data interface{}
}
package lib_allinpay
// CreateMember 创建会员
func (c *Client) CreateMember(param CreateMember) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//ApplyBindAcct 绑定会员标识-用于小程序支付等
func (c *Client) ApplyBindAcct(param ApplyBindAcct) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetMemberInfo 查询会员
func (c *Client) GetMemberInfo(param GetMemberInfo) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryBankCard 查询绑定银行卡
func (c *Client) QueryBankCard(param QueryBankCard) (result *QueryBankCardResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
package lib_allinpay
type CreateMember struct {
BizUserId string `json:"bizUserId"`
MemberType uint8 `json:"memberType"`
Source uint8 `json:"source"`
}
func (CreateMember) apiName() string {
return "allinpay.yunst.memberService.createMember"
}
type ApplyBindAcct struct {
BizUserId string `json:"bizUserId"`
OperationType string `json:"operationType"`
AcctType string `json:"acctType"`
Acct string `json:"acct"`
}
func (ApplyBindAcct) apiName() string {
return "allinpay.yunst.memberService.applyBindAcct"
}
type GetMemberInfo struct {
BizUserId string `json:"bizUserId"`
}
func (GetMemberInfo) apiName() string {
return "allinpay.yunst.memberService.getMemberInfo"
}
type QueryBankCard struct {
BizUserId string `json:"bizUserId"`
CardNo string `json:"cardNo"`
}
func (QueryBankCard) apiName() string {
return "allinpay.yunst.memberService.queryBankCard"
}
type QueryBankCardResponse struct {
OpenResponse
Data QueryBankCardResponseData
}
type QueryBankCardResponseData struct {
BindCardList []BindCard
}
type BindCard struct {
BankCardNo string
BankName string
BindState string
Phone string
BranchBankName string
}
package lib_allinpay
//ConsumeApply 绑定会员标识-用于小程序支付等
func (c *Client) ConsumeApply(param ConsumeApply) (result *WxMiniPayOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetOrderDetail 绑定会员标识-用于小程序支付等
func (c *Client) GetOrderDetail(param GetOrderDetail) (result *GetOrderDetailOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//Refund 退款
func (c *Client) Refund(param Refund) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryReserveFundBalance 查询平台头寸信息(账户信息)
func (c *Client) QueryReserveFundBalance(param QueryReserveFundBalance) (result *QueryReserveFundBalanceResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryBalance 查询会员账户信息
func (c *Client) QueryBalance(param QueryBalance) (result *QueryBalanceResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//WithdrawApply 提现
func (c *Client) WithdrawApply(param WithdrawApply) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//QueryInExpDetail 查询账户收支明细
func (c *Client) QueryInExpDetail(param QueryInExpDetail) (result *QueryInExpDetailResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
//GetPayeeFundsInTransitDetail 收款方在途资金明细查询
func (c *Client) GetPayeeFundsInTransitDetail(param GetPayeeFundsInTransitDetail) (result *DefaultOpenResponse, err error) {
err = c.doRequest("POST", param, &result)
return result, err
}
package lib_allinpay
type ConsumeApply struct {
PayerId string `json:"payerId"`
BizOrderNo string `json:"bizOrderNo"`
RecieverId string `json:"recieverId"`
Amount int64 `json:"amount"`
Fee int64 `json:"fee"`
ValidateType uint8 `json:"validateType"`
BackUrl string `json:"backUrl"`
OrderExpireDatetime string `json:"orderExpireDatetime"`
PayMethod *PayMethod `json:"payMethod"`
IndustryCode string `json:"industryCode"`
IndustryName string `json:"industryName"`
Source int `json:"source"`
Summary string `json:"summary"`
}
type PayMethod struct {
WECHATPAY_MINIPROGRAM_ORG *WECHATPAY_MINIPROGRAM_ORG `json:"WECHATPAY_MINIPROGRAM_ORG"`
}
type WECHATPAY_MINIPROGRAM_ORG struct {
VspCusid string `json:"vspCusid"`
SubAppid string `json:"subAppid"`
LimitPay string `json:"limitPay"`
Amount int64 `json:"amount"`
Acct string `json:"acct"`
}
func (ConsumeApply) apiName() string {
return "allinpay.yunst.orderService.consumeApply"
}
type WxMiniPayOpenResponse struct {
OpenResponse
Data WxMiniPayOpenResponseData
}
type WxMiniPayOpenResponseData struct {
PayInterfaceOutTradeNo string
OrderNo string
PayInfo string
BizUserId string
BizOrderNo string
}
type GetOrderDetail struct {
BizOrderNo string `json:"bizOrderNo"`
}
func (GetOrderDetail) apiName() string {
return "allinpay.yunst.orderService.getOrderDetail"
}
type GetOrderDetailOpenResponse struct {
OpenResponse
Data GetOrderDetailOpenResponseData
}
type GetOrderDetailOpenResponseData struct {
Amount string
BizOrderNo string
BuyerBizUserId string
OrderStatus string
OrderNo string
ErrorMessage string
PayDatetime string
}
type Refund struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
OriBizOrderNo string `json:"oriBizOrderNo"`
Amount int64 `json:"amount"`
FeeAmount int64 `json:"feeAmount"`
RefundType string `json:"refundType"`
BackUrl string `json:"backUrl"`
RefundList []RefundAccount `json:"refundList"`
}
type RefundAccount struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
Amount int64 `json:"amount"`
}
func (Refund) apiName() string {
return "allinpay.yunst.orderService.refund"
}
type QueryReserveFundBalance struct {
}
func (QueryReserveFundBalance) apiName() string {
return "allinpay.yunst.merchantService.queryReserveFundBalance"
}
type QueryReserveFundBalanceResponse struct {
OpenResponse
Data QueryReserveFundBalanceResponseData
}
type QueryReserveFundBalanceResponseData struct {
AccountName string
AccountNo string
Balance string
DefClr string
}
type QueryBalance struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
}
func (QueryBalance) apiName() string {
return "allinpay.yunst.orderService.queryBalance"
}
type QueryBalanceResponse struct {
OpenResponse
Data QueryBalanceResponseData
}
type QueryBalanceResponseData struct {
AllAmount string
FreezenAmount string
}
type WithdrawApply struct {
AccountSetNo string `json:"accountSetNo"`
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
Amount int64 `json:"amount"`
Fee int64 `json:"fee"`
ValidateType uint8 `json:"validateType"`
BackUrl string `json:"backUrl"`
OrderExpireDatetime string `json:"orderExpireDatetime"`
BankCardNo string `json:"bankCardNo"`
BankCardPro uint8 `json:"bankCardPro"`
WithdrawType string `json:"withdrawType"`
IndustryCode string `json:"industryCode"`
IndustryName string `json:"industryName"`
Source uint8 `json:"source"`
Summary string `json:"summary"`
}
func (WithdrawApply) apiName() string {
return "allinpay.yunst.orderService.withdrawApply"
}
type WithdrawApplyResponseData struct {
PayInterfaceOutTradeNo string
BuyerBizUserId string
Amount int64
OrderNo string
ExtendInfo string
PayDatetime string
Acct string
BizOrderNo string
Status string
}
type QueryInExpDetail struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
DateStart string `json:"dateStart"`
DateEnd string `json:"dateEnd"`
StartPosition int `json:"startPosition"`
QueryNum int `json:"queryNum"`
TradeType string `json:"tradeType"`
}
func (QueryInExpDetail) apiName() string {
return "allinpay.yunst.orderService.queryInExpDetail"
}
type QueryInExpDetailResponse struct {
OpenResponse
Data QueryInExpDetailResponseData
}
type QueryInExpDetailResponseData struct {
BizUserId string
TotalNum string
InExpDetail []InExpDetail
ExtendInfo string
}
type InExpDetail struct {
TradeNo string
AccountSetName string
ChangeTime string
CurAmount int64
OriAmount int64
ChgAmount int64
CurFreezenAmount int64
BizOrderNo string
TradeType string
Type string
Remark string
ExtendInfo string
}
type GetPayeeFundsInTransitDetail struct {
BizUserId string `json:"bizUserId"`
BizOrderNo string `json:"bizOrderNo"`
DateStart string `json:"dateStart"`
DateEnd string `json:"dateEnd"`
AccountSetNo string `json:"accountSetNo"`
}
func (GetPayeeFundsInTransitDetail) apiName() string {
return "allinpay.yunst.orderService.getPayeeFundsInTransitDetail"
}
type PayNotifyData struct {
Amount *int `json:"amount"`
OrderNo *string `json:"orderNo"`
ChannelFee *string `json:"channelFee"`
ChannelPaytime *string `json:"channelPaytime"`
ExtendInfo *string `json:"extendInfo"`
PayInterfaceOutTradeNo *string `json:"payInterfaceOutTradeNo"`
BuyerBizUserId *string `json:"buyerBizUserId"`
Cusid *string `json:"cusid"`
PayInterfacetrxcode *string `json:"payInterfacetrxcode"`
PayDatetime *string `json:"payDatetime"`
Acct *string `json:"acct"`
BizOrderNo *string `json:"bizOrderNo"`
Status *string `json:"status"`
RefundWhereabouts *int `json:"refundWhereabouts"`
OriOrderNo *string `json:"oriOrderNo"`
OriBizOrderNo *string `json:"oriBizOrderNo"`
}
package lib_allinpay
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"golang.org/x/crypto/pkcs12"
"io/ioutil"
"os"
)
//通过公钥的文件路径加载公钥
func loadPublicKeyWithPath(path string) (publicKey *rsa.PublicKey, err error) {
//读取证书并解码
pemTmp, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf(err.Error())
}
certBlock, _ := pem.Decode(pemTmp)
if certBlock == nil {
return nil, fmt.Errorf(err.Error())
}
//证书解析
certBody, err := x509.ParseCertificate(certBlock.Bytes)
if err != nil {
fmt.Println(err)
return
}
publicKey, ok := certBody.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", path)
}
return publicKey, nil
}
func loadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
block, _ := pem.Decode([]byte(publicKeyStr))
if block == nil {
return nil, errors.New("decode public key error")
}
//if block.Type != "PUBLIC KEY" {
// return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
//}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse public key err:%s", err.Error())
}
publicKey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
}
return publicKey, nil
}
func getPrivateKey(privateKeyPath, privatePassword string) (*rsa.PrivateKey, error) {
f, err := os.Open(privateKeyPath)
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
// 因为pfx证书公钥和密钥是成对的,所以要先转成pem.Block
blocks, err := pkcs12.ToPEM(bytes, privatePassword)
if err != nil {
return nil, err
}
if len(blocks) != 2 {
return nil, errors.New("解密错误")
}
// 拿到第一个block,用x509解析出私钥(当然公钥也是可以的)
privateKey, err := x509.ParsePKCS1PrivateKey(blocks[0].Bytes)
if err != nil {
return nil, err
}
return privateKey, nil
}
func RSASignWithKey(plaintext []byte, key *rsa.PrivateKey, hash crypto.Hash) ([]byte, error) {
var h = hash.New()
h.Write(plaintext)
var hashed = h.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, key, hash, hashed)
}
func RSAVerifyWithKey(ciphertext, sign []byte, key *rsa.PublicKey, hash crypto.Hash) error {
var h = hash.New()
h.Write(ciphertext)
var hashed = h.Sum(nil)
return rsa.VerifyPKCS1v15(key, hash, hashed, sign)
}
package page
type Page struct {
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
Total int `json:"total"`
}
type Data struct {
Page
List interface{} `json:"list"`
}
package page
type ParamPage struct {
PageNum int `json:"pageNum"`
PageSize int `json:"pageSize"`
}
type Param struct {
Column string
Op string
Value interface{}
}
package sqlOp
const Equal = "="
const Like = "like"
const LessThan = "<"
const GreatThan = ">"
const LessThanOrEqual = "<="
const GreatThanOrEqual = ">="
func DimLeft(s string) string {
return "%" + s
}
func DimRight(s string) string {
return s + "%"
}
func DimAll(s string) string {
return "%" + s + "%"
}
package util
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
)
func imgToBase64() {
imgUrl := "https://img.ipcfun.com/uploads/ishoulu/pic/2013/05/9215193abd60b5ff099795216.jpg"
//获取远端图片
res, err := http.Get(imgUrl)
if err != nil {
fmt.Println("A error occurred!")
return
}
defer res.Body.Close()
// 读取获取的[]byte数据
data, _ := ioutil.ReadAll(res.Body)
imageBase64 := base64.StdEncoding.EncodeToString(data)
fmt.Println("base64", imageBase64)
}
package util
import (
"bytes"
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
"sort"
)
func Map2SHA256WithRSA(params map[string]interface{}, key string) (result string) {
var keys []string
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var buf bytes.Buffer
for _, k := range keys {
buf.WriteString(fmt.Sprintf("%s=%v&", k, params[k]))
}
cleartext := buf.String()[:buf.Len()-1]
step3 := md5.Sum([]byte(cleartext))
shaNew := sha256.New()
shaNew.Write(step3[:])
priKey, err := utils.LoadPrivateKey(key)
if err != nil {
exception.ThrowsErr(err)
}
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, shaNew.Sum(nil))
if err != nil {
exception.ThrowsErr(err)
}
return base64.StdEncoding.EncodeToString(signature)
}
...@@ -2,7 +2,6 @@ package util ...@@ -2,7 +2,6 @@ package util
import ( import (
"encoding/json" "encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"net/url" "net/url"
"sort" "sort"
"strconv" "strconv"
...@@ -94,7 +93,7 @@ func StrToMapStr(obj string) map[string]string { ...@@ -94,7 +93,7 @@ func StrToMapStr(obj string) map[string]string {
func ToObject(txt string, p interface{}) { func ToObject(txt string, p interface{}) {
err := json.Unmarshal([]byte(txt), p) err := json.Unmarshal([]byte(txt), p)
if err != nil { if err != nil {
exception.ThrowsErr(err) panic(err)
} }
} }
......
package Stream
import (
"fmt"
"strings"
)
//泛型类型定义
type T interface{}
type U interface{}
//流计算数据结构定义
type Stream struct {
Head T
Tail *Stream
Length int
NotEmpty bool
}
var Nil = Stream{}
func Generate(r Stream, f func(Stream) T, m int) Stream {
if m == 1 {
return r
} else {
return Generate(New(f(r), &r), f, m-1)
}
}
func New(head T, tail *Stream) Stream {
return Stream{head, tail, tail.Length + 1, true}
}
func (s Stream) Add(i T) Stream {
return New(i, &s)
}
func (s Stream) Adderall(i ...T) Stream {
for _, v := range i {
s = s.Add(v)
}
return s
}
//左折叠 用于实现 reduce 的功能
func (s Stream) FoldLeft(i U, f func(U, T) U) U {
if s.NotEmpty {
return s.Tail.FoldLeft(f(i, s.Head), f)
} else {
return i
}
}
//右折叠
func (s Stream) FoldRight(i U, f func(U, T) U) U {
if s.NotEmpty {
return f(s.Tail.FoldRight(i, f), s.Head)
} else {
return i
}
}
//合并两个 Stream
func (s Stream) Merge(t Stream) Stream {
if t.NotEmpty {
return t.FoldRight(s, func(u U, t T) U {
return u.(Stream).Add(t)
}).(Stream)
} else {
return s
}
}
//倒序
func (s Stream) Reverse() Stream {
return s.FoldLeft(Nil, func(u U, t T) U {
return u.(Stream).Add(t)
}).(Stream)
}
//Map
func (s Stream) Map(f func(T) U) Stream {
return s.FoldRight(Nil, func(u U, t T) U {
return u.(Stream).Add(f(t))
}).(Stream)
}
//Reduce
func (s Stream) Reduce(i T, f func(T, T) T) T {
if s.NotEmpty {
return s.Tail.Reduce(f(i, s.Head), f)
} else {
return i
}
}
//过滤
func (s Stream) Filter(f func(T) bool) Stream {
return s.FoldRight(Nil, func(u U, t T) U {
if f(t) {
return u.(Stream).Add(t)
} else {
return u
}
}).(Stream)
}
//归并排序
func (s Stream) Sort(c func(T, T) bool) Stream {
n := s.Length / 2
if n == 0 {
return s
} else {
x, y := split(s, Nil, n)
return merge(x.Sort(c), y.Sort(c), c)
}
}
func split(x, y Stream, n int) (Stream, Stream) {
if n == 0 || !x.NotEmpty {
return x, y
}
return split(*x.Tail, y.Add(x.Head), n-1)
}
func merge(x, y Stream, c func(T, T) bool) Stream {
if !x.NotEmpty {
return y
}
if !y.NotEmpty {
return x
}
if c(x.Head, y.Head) {
return merge(*x.Tail, y, c).Add(x.Head)
} else {
return merge(x, *y.Tail, c).Add(y.Head)
}
}
//格式化显示 Stream 的所有项
func (s Stream) ToString() string {
return "{" + strings.Join(s.FoldRight([]string{}, func(u U, t T) U {
return append(u.([]string), fmt.Sprintf("%v", t))
}).([]string), ",") + "}"
}
...@@ -2,9 +2,6 @@ package util ...@@ -2,9 +2,6 @@ package util
import ( import (
"encoding/json" "encoding/json"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
"math/rand" "math/rand"
"strconv" "strconv"
) )
...@@ -20,43 +17,6 @@ func FandomString(strlen int) string { ...@@ -20,43 +17,6 @@ func FandomString(strlen int) string {
return string(result) return string(result)
} }
func ParamUint32(c *gin.Context, key string) uint32 {
v := c.Query(key)
if v == "" {
return 0
}
i, err := strconv.Atoi(v)
if err != nil {
exception.ThrowsErrS("参数类型错误:请传入正确的数字")
}
return uint32(i)
}
func ParamUint8(c *gin.Context, key string) uint8 {
v := c.Query(key)
if v == "" {
return 0
}
i, err := strconv.Atoi(v)
if err != nil {
exception.ThrowsErrS("参数类型错误:请传入正确的数字")
}
return uint8(i)
}
func Param(c *gin.Context, key string) string {
v := c.Query(key)
return v
}
func Path(c *gin.Context, key string) string {
v := c.Param(key)
if v == "" {
exception.ThrowsErrS("参数[" + key + "]必填")
}
return v
}
// Strval 获取变量的字符串值 // Strval 获取变量的字符串值
// 浮点型 3.0将会转换成字符串3, "3" // 浮点型 3.0将会转换成字符串3, "3"
// 非数值或字符类型的变量将会被转换成JSON格式字符串 // 非数值或字符类型的变量将会被转换成JSON格式字符串
...@@ -126,13 +86,3 @@ func IsNil(i interface{}) bool { ...@@ -126,13 +86,3 @@ func IsNil(i interface{}) bool {
} }
return false return false
} }
func YuanToFen(money float64) int64 {
v12 := decimal.NewFromFloat(float64(money) * 100).Round(0).BigInt().Int64()
return v12
}
func FenToYuan(money int64) float64 {
v12, _ := decimal.NewFromFloat(float64(money) / 100).Round(2).Float64()
return v12
}
package util
import (
"crypto/aes"
"crypto/sha1"
"encoding/hex"
"errors"
"strings"
)
//AesEncryptECBAllin 通联数据加密
func AesEncryptECBAllin(src, key string) (string, error) {
data, err := AesEncryptECB(src, key)
return strings.ToUpper(data), err
}
//AesDecryptECBAllin 通联数据解密
func AesDecryptECBAllin(src, key string) (string, error) {
src = strings.ToLower(src)
data, err := AesDecryptECB(src, key)
return data, err
}
func AesEncryptECB(src, key string) (string, error) {
data, err := aesEncryptECB([]byte(src), []byte(key))
eStr := hex.EncodeToString(data)
return eStr, err
}
func AesDecryptECB(src, key string) (string, error) {
data, err := hex.DecodeString(src)
if err != nil {
return "", err
}
re, err := aesDecryptECB([]byte(data), []byte(key))
return string(re), err
}
func aesEncryptECB(src []byte, key []byte) ([]byte, error) {
key, err := aesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted, nil
}
func aesDecryptECB(encrypted []byte, key []byte) ([]byte, error) {
key, err := aesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
decrypted := make([]byte, len(encrypted))
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim], nil
}
func aesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
a := sha1Key(sha1Key(keyBytes))
maxLen := len(a)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("密钥长度非法")
}
return a[0:realLen], nil
}
func sha1Key(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
package main
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/util/aes"
)
func main() {
org := "18090279887"
key := "B9qzpSpA7llER2fpowePNMNcArCHJLlO"
fmt.Println("原生数据:" + org)
// 加密
res, err := util.AesEncryptECBAllin(org, key)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("加密结果:" + res)
// 解密
de, err := util.AesDecryptECBAllin(res, key)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("解密结果:" + de)
}
package util
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func LoadPrivateKey(privateKeyStr string) (privateKey *rsa.PrivateKey, err error) {
block, _ := pem.Decode([]byte(buildFullPrivateKey(privateKeyStr)))
if block == nil {
return nil, fmt.Errorf("decode private key err")
}
if block.Type != "PRIVATE KEY" {
return nil, fmt.Errorf("the kind of PEM should be PRVATE KEY")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse private key err:%s", err.Error())
}
privateKey, ok := key.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa private key", privateKeyStr)
}
return privateKey, nil
}
func buildFullPrivateKey(privateKey string) string {
preLine := "-----BEGIN PRIVATE KEY-----\n"
endLine := "\n-----END PRIVATE KEY-----"
return preLine + privateKey + endLine
}
// LoadPublicKey 通过公钥的文本内容加载公钥
func LoadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
block, _ := pem.Decode([]byte(buildFullPublicKey(publicKeyStr)))
if block == nil {
return nil, fmt.Errorf("decode public key error")
}
if block.Type != "PUBLIC KEY" {
return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
}
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("parse public key err:%s", err.Error())
}
publicKey, ok := key.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
}
return publicKey, nil
}
func buildFullPublicKey(publicKey string) string {
preLine := "-----BEGIN PUBLIC KEY-----\n"
endLine := "\n-----END PUBLIC KEY-----"
return preLine + publicKey + endLine
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment