From cb808f9c685314c1de6d4426330899bc19979bf4 Mon Sep 17 00:00:00 2001 From: sugarBecomer Date: Thu, 13 Nov 2025 00:17:49 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E9=80=82=E9=85=8D=E5=8D=97?= =?UTF-8?q?=E6=98=8C=E7=90=86=E5=B7=A5=E5=AD=A6=E9=99=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.toml | 4 +- .../cpdaily/cryptoutil/des_decrypt_test.go | 76 +++++++ .../application/cpdaily/cryptoutil/rsa.go | 122 ++++++++++ .../cpdaily/cryptoutil/rsa_test.go | 54 +++++ internal/application/cpdaily/login/auto.go | 3 + internal/application/cpdaily/login/nut.go | 213 ++++++++++++++++++ internal/application/cpdaily/login/ocr.go | 54 ++--- .../application/cpdaily/taskhelper/sign.go | 2 +- internal/utils/file.go | 4 +- 9 files changed, 502 insertions(+), 30 deletions(-) create mode 100644 internal/application/cpdaily/cryptoutil/des_decrypt_test.go create mode 100644 internal/application/cpdaily/cryptoutil/rsa.go create mode 100644 internal/application/cpdaily/cryptoutil/rsa_test.go create mode 100644 internal/application/cpdaily/login/nut.go diff --git a/config.toml b/config.toml index 4cd0a58..ca19529 100644 --- a/config.toml +++ b/config.toml @@ -42,6 +42,6 @@ baseUrl = "http://s3.out" bucket = "likedream" [cpdaily] -appVersion = "5.7.0" +appVersion = "9.7.2" systemVersion = "iOS 17" -calVersion = "3.0.0" \ No newline at end of file +calVersion = "firstv" \ No newline at end of file diff --git a/internal/application/cpdaily/cryptoutil/des_decrypt_test.go b/internal/application/cpdaily/cryptoutil/des_decrypt_test.go new file mode 100644 index 0000000..4f0a607 --- /dev/null +++ b/internal/application/cpdaily/cryptoutil/des_decrypt_test.go @@ -0,0 +1,76 @@ +package cryptoutil + +import ( + "crypto/md5" + "encoding/base64" + "encoding/hex" + "net/url" + "strings" + "testing" + + "github.com/gogf/gf/v2/container/gvar" +) + +func TestDesDecrypt(t *testing.T) { + decodeString, _ := base64.StdEncoding.DecodeString("X3/auV/FUP3Fj9iou6jNosFm9+6oiZ08pQlSt2qUlEhBEZXchcrXZJ96OsPIH4tfc6oRqdvlnObFx+uJfKA9oEuQQURvvDcDLz/1uAsQHXQIXNaW1Bwt9vdo4e1Sxzvt2sBxcHZXlsAPnxRw8UCM6DnoU4kHXF45A2i9wQpzH1cgKsoN/tWLRPYOBSMsPfbsch+wFgFpkQGRWNM9E0CVmpwZJWn946McO4HbMJngTeT5Df8YOUgpkFdccMKrJyPqE7UMOc56YLkPjb/wzmFyd1/HFCUbJwwdhOueH70GSpsH5LrWEhw7jvf2VBmnm669E2uvQjeCtPI1SvVuf7WP9Srp1BXpMtfK") + decrypt := DesDecrypt(decodeString, Cat) + str := "{\"lon\":\"113.045246\",\"lat\":\"28.077659\",\"model\":\"847b5b9c-2d97-41ec-8a5d-e9ac79da090d\",\"appVersion\":\"9.7.2\",\"userId\":\"430181200504150038\",\"systemName\":\"android\",\"deviceId\":\"09E46EC9-57C1-4724-BE53-5879CA80A2A0\",\"cpdailyVersion\":\"9.7.2\",\"systemVersion\":\"iOS 17\"}" + encrypt := DesEncrypt([]byte(str), Cat) + toString := base64.StdEncoding.EncodeToString(encrypt) + t.Log(toString) + t.Log(string(decrypt)) + d2, _ := base64.StdEncoding.DecodeString("0u7hBd+6O11ZaGsT51FUAVfB72waqtTx5oQQLVEEAuCM29x8lQc41i9/dF6+9wjQNC05jdJTBmHlwFoLD09hfsnQWSyjl/ys124RUQL3r/Um5AwNdKiJE24YQsyQlP3ZamUIFlrNSxmn/DfZ/jR9oZhiVKZSlygA2LNLxtNOyk4rETfqKpZKFOnThbXy5Hf779jUDmPNwn1ZrdWN8UHm6wO+EahrrX60vC02VUHs7r3rMrDWZjBJ57eSgD0QwZabcIb/u9kx1AD8OAxINar3X+N+uAhfrxjHd6v6OVvnc2I9iPLEGNFRKZ94jq64hnATOSH6S/IR/QbDoxebWpGUXm3ALYZeoni09uyhG7IE5NtRw/OmqYtdknrs+c0qyOOBkvxPlqKo+SV4qq7xtrn9RWeZIigiyM8mVtdovN1T/x3DnHxd/AYoSS3/cGkg+2QHzWey/Xf5c4g0EvhaGlE0C7ejKIn5wp0XeHyvAjm4ZVyUhgTN2dZVCQ6ChxXOpLnVDWPNeeZ9vysqVl1ZSkQdCz20gy3p9RfYuArluQqjwIoWQe632Cc/Ep++99V5Tc9iIlLr93PfxFaJJfov3avLKw==") + d := AesDecryptForCat(d2) + t.Log(d) + + form := map[string]*gvar.Var{ + "appVersion": gvar.New("9.7.2"), + "bodyString": gvar.New("0u7hBd+6O11ZaGsT51FUAVfB72waqtTx5oQQLVEEAuCM29x8lQc41i9/dF6+9wjQNC05jdJTBmHlwFoLD09hfsnQWSyjl/ys124RUQL3r/Um5AwNdKiJE24YQsyQlP3ZamUIFlrNSxmn/DfZ/jR9oZhiVKZSlygA2LNLxtNOyk4rETfqKpZKFOnThbXy5Hf779jUDmPNwn1ZrdWN8UHm6wO+EahrrX60vC02VUHs7r3rMrDWZjBJ57eSgD0QwZabcIb/u9kx1AD8OAxINar3X+N+uAhfrxjHd6v6OVvnc2I9iPLEGNFRKZ94jq64hnATOSH6S/IR/QbDoxebWpGUXm3ALYZeoni09uyhG7IE5NtRw/OmqYtdknrs+c0qyOOBkvxPlqKo+SV4qq7xtrn9RWeZIigiyM8mVtdovN1T/x3DnHxd/AYoSS3/cGkg+2QHzWey/Xf5c4g0EvhaGlE0C7ejKIn5wp0XeHyvAjm4ZVyUhgTN2dZVCQ6ChxXOpLnVDWPNeeZ9vysqVl1ZSkQdCz20gy3p9RfYuArluQqjwIoWQe632Cc/Ep++99V5Tc9iIlLr93PfxFaJJfov3avLKw=="), + "calVersion": gvar.New("firstv"), + "deviceId": gvar.New("09E46EC9-57C1-4724-BE53-5879CA80A2A0"), + "lat": gvar.New("28.077659"), + "lon": gvar.New("113.045246"), + "model": gvar.New("847b5b9c-2d97-41ec-8a5d-e9ac79da090d"), + "systemName": gvar.New("android"), + "systemVersion": gvar.New("iOS 17"), + "userId": gvar.New("430181200504150038"), + "version": gvar.New("first_v4"), + } + sign := GetSubmitSign(form) + t.Log(sign) +} + +const submitSignSalt = "hru89rwr87Nthifa" // 请根据实际情况替换为真实盐值 + +func GetSubmitSign(form map[string]*gvar.Var) string { + // 按照指定顺序构建哈希数据 + keys := []string{ + "appVersion", + "bodyString", + "deviceId", + "lat", + "lon", + "model", + "systemName", + "systemVersion", + "userId", + } + + var sb strings.Builder + for _, key := range keys { + val := "" + if v, ok := form[key]; ok && v != nil { + val = v.String() + } + // 这里是 key=UrlEncode(key)&,注意是对 key 进行 url encode + sb.WriteString(key) + sb.WriteString("=") + sb.WriteString(url.QueryEscape(val)) + sb.WriteString("&") + } + sb.WriteString(submitSignSalt) + + // 计算MD5 + hash := md5.Sum([]byte(sb.String())) + return hex.EncodeToString(hash[:]) +} diff --git a/internal/application/cpdaily/cryptoutil/rsa.go b/internal/application/cpdaily/cryptoutil/rsa.go new file mode 100644 index 0000000..9dfce94 --- /dev/null +++ b/internal/application/cpdaily/cryptoutil/rsa.go @@ -0,0 +1,122 @@ +package cryptoutil + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "math/big" +) + +// RSAKeyPair RSA密钥对结构体 +type RSAKeyPair struct { + n *big.Int // 模数 + e *big.Int // 公钥指数 +} + +// NewRSAKeyPair 创建RSA密钥对 +// exponent: 公钥指数的十六进制字符串,通常是 "10001" (65537) +// privateExponent: 私钥指数的十六进制字符串,加密时可以为空 +// modulus: 模数的十六进制字符串 +func NewRSAKeyPair(exponent, privateExponent, modulus string) (*RSAKeyPair, error) { + // 解析公钥指数 + e := new(big.Int) + if _, ok := e.SetString(exponent, 16); !ok { + return nil, fmt.Errorf("invalid exponent: %s", exponent) + } + + // 解析模数 + n := new(big.Int) + if _, ok := n.SetString(modulus, 16); !ok { + return nil, fmt.Errorf("invalid modulus: %s", modulus) + } + + return &RSAKeyPair{ + n: n, + e: e, + }, nil +} + +// Encrypt 使用公钥加密数据,返回十六进制字符串 +func (k *RSAKeyPair) Encrypt(plaintext string) (string, error) { + ciphertext, err := k.EncryptBytes([]byte(plaintext)) + if err != nil { + return "", err + } + // 返回十六进制编码的密文 + return hex.EncodeToString(ciphertext), nil +} + +// EncryptBytes 使用公钥加密字节数据,返回加密后的字节 +// 使用 PKCS1v15 填充方式,兼容 JavaScript RSA 实现 +func (k *RSAKeyPair) EncryptBytes(plaintext []byte) ([]byte, error) { + // 计算密钥长度(字节) + keySize := (k.n.BitLen() + 7) / 8 + + // PKCS1v15 填充 + padded, err := pkcs1v15Pad(plaintext, keySize) + if err != nil { + return nil, err + } + + // 将填充后的数据转换为大整数 + m := new(big.Int).SetBytes(padded) + + // 执行 RSA 加密: c = m^e mod n + c := new(big.Int).Exp(m, k.e, k.n) + + // 将结果转换为字节数组,确保长度与密钥长度一致 + ciphertext := c.Bytes() + if len(ciphertext) < keySize { + // 如果结果长度不足,在前面填充零 + result := make([]byte, keySize) + copy(result[keySize-len(ciphertext):], ciphertext) + return result, nil + } + + return ciphertext, nil +} + +// pkcs1v15Pad 实现 PKCS#1 v1.5 填充 +func pkcs1v15Pad(data []byte, keySize int) ([]byte, error) { + if len(data) > keySize-11 { + return nil, fmt.Errorf("data too long: %d bytes (max %d)", len(data), keySize-11) + } + + // PKCS1v15 格式: 0x00 || 0x02 || PS || 0x00 || data + // 其中 PS 是随机非零字节,长度至少为 8 字节 + padLen := keySize - len(data) - 3 + + padded := make([]byte, keySize) + padded[0] = 0x00 + padded[1] = 0x02 + + // 生成随机非零字节作为填充 + ps := make([]byte, padLen) + _, err := rand.Read(ps) + if err != nil { + return nil, fmt.Errorf("failed to generate random padding: %w", err) + } + + // 确保所有填充字节都是非零 + for i := 0; i < padLen; i++ { + for ps[i] == 0 { + rand.Read(ps[i : i+1]) + } + padded[2+i] = ps[i] + } + + padded[2+padLen] = 0x00 + copy(padded[3+padLen:], data) + + return padded, nil +} + +// GetModulus 获取模数 +func (k *RSAKeyPair) GetModulus() *big.Int { + return k.n +} + +// GetExponent 获取公钥指数 +func (k *RSAKeyPair) GetExponent() *big.Int { + return k.e +} diff --git a/internal/application/cpdaily/cryptoutil/rsa_test.go b/internal/application/cpdaily/cryptoutil/rsa_test.go new file mode 100644 index 0000000..35ac347 --- /dev/null +++ b/internal/application/cpdaily/cryptoutil/rsa_test.go @@ -0,0 +1,54 @@ +package cryptoutil + +import ( + "testing" +) + +func TestRSAKeyPair(t *testing.T) { + // 使用你提供的参数创建 RSA 密钥对 + exponent := "10001" + modulus := "a1155dc73de04614604cbed62cc3b3198a639eb7b7d19cc2dfe3e787fe435f1464beee42a9a3cab6f1d3bfe66cd00317220ee770fd779b24c12c7698e251e875" + + keyPair, err := NewRSAKeyPair(exponent, "", modulus) + if err != nil { + t.Fatalf("创建 RSA 密钥对失败: %v", err) + } + + // 测试加密 + plaintext := "241703070163" + ciphertext, err := keyPair.Encrypt(plaintext) + if err != nil { + t.Fatalf("加密失败: %v", err) + } + + t.Logf("明文: %s", plaintext) + t.Logf("密文(十六进制): %s", ciphertext) + + // 验证密文不为空 + if len(ciphertext) == 0 { + t.Error("密文为空") + } +} + +func TestRSAKeyPair_EncryptBytes(t *testing.T) { + exponent := "10001" + modulus := "a1155dc73de04614604cbed62cc3b3198a639eb7b7d19cc2dfe3e787fe435f1464beee42a9a3cab6f1d3bfe66cd00317220ee770fd779b24c12c7698e251e875" + + keyPair, err := NewRSAKeyPair(exponent, "", modulus) + if err != nil { + t.Fatalf("创建 RSA 密钥对失败: %v", err) + } + + // 测试字节加密 + plaintext := []byte("Test data 测试数据") + ciphertext, err := keyPair.EncryptBytes(plaintext) + if err != nil { + t.Fatalf("字节加密失败: %v", err) + } + + if len(ciphertext) == 0 { + t.Error("密文字节为空") + } + + t.Logf("密文长度: %d bytes", len(ciphertext)) +} diff --git a/internal/application/cpdaily/login/auto.go b/internal/application/cpdaily/login/auto.go index b468fde..202f459 100644 --- a/internal/application/cpdaily/login/auto.go +++ b/internal/application/cpdaily/login/auto.go @@ -7,6 +7,9 @@ import ( func GetCpdailyLoginBySchoolInfo(ctx context.Context, info *school.SchoolDetailInfo) CpdailyLogin { switch info.Id { + // 南昌理工学院 + case "d6e8f2ca-10b2-4599-bdb8-4b33d419658d": + return NewNut(ctx) default: if info.IsIap() { return NewIap(ctx) diff --git a/internal/application/cpdaily/login/nut.go b/internal/application/cpdaily/login/nut.go new file mode 100644 index 0000000..2007e3b --- /dev/null +++ b/internal/application/cpdaily/login/nut.go @@ -0,0 +1,213 @@ +package login + +import ( + "bytes" + "context" + "fmt" + "io" + "likedream-goframe/internal/application/cookiejar" + "likedream-goframe/internal/application/cpdaily/cryptoutil" + "likedream-goframe/internal/application/cpdaily/school" + "likedream-goframe/internal/application/httpclient" + "likedream-goframe/internal/common/errors" + "likedream-goframe/internal/utils" + "net/http" + "net/url" + "strings" + + "github.com/PuerkitoBio/goquery" + "github.com/bytedance/sonic" + "github.com/samber/oops" + "resty.dev/v3" +) + +// 南阳理工学院登录实现 RSA加密 & 验证码必出 +type CpdailyNutLogin struct { + client *resty.Client +} + +func (c CpdailyNutLogin) Login(ctx context.Context, schoolDetail *school.SchoolDetailInfo, username, password string) { + jar := cookiejar.NewPersistCookieJar() + + c.client = c.client.SetCookieJar(jar).SetRedirectPolicy(resty.FlexibleRedirectPolicy(20)) + + // 获取合法的登录URL + loginUrl := getCasValidLoginUrl(schoolDetail) + + // 请求登录页面并获取真正的登录URL + loginPageResponse, err := c.client.R(). + WithContext(ctx). + Get(loginUrl) + utils.OkOrPanic(err) + + defer loginPageResponse.Body.Close() + loginPageBytes, err := io.ReadAll(loginPageResponse.Body) + utils.OkOrPanic(err) + loginResponseUrl := loginPageResponse.RawResponse.Request.URL + // 关闭client的重定向 + c.client = c.client.SetRedirectPolicy(resty.NoRedirectPolicy()) + + // 解析登录页面 + loginPage, err := goquery.NewDocumentFromReader(bytes.NewReader(loginPageBytes)) + utils.OkOrPanic(err) + // 判断登录类型 + var ( + allInputs = map[string]string{} + fm1Node = loginPage.Find("#fm1").First() + ) + inputs := fm1Node.Find("input") + + for _, input := range inputs.EachIter() { + name, exists := input.Attr("name") + if !exists { + continue + } + value, _ := input.Attr("value") + allInputs[name] = value + } + + allInputs["username"] = username + + // 处理密码 + + type NutPubKeyResponse struct { + Modulus string `json:"modulus"` + Exponent string `json:"exponent"` + } + var pubKey NutPubKeyResponse + pubKeyResponse, err := c.client.R().Get(getNutPubKey(loginResponseUrl)) + utils.OkOrPanic(err) + defer pubKeyResponse.Body.Close() + pubKeyBytes, err := io.ReadAll(pubKeyResponse.Body) + utils.OkOrPanic(err) + sonic.Unmarshal(pubKeyBytes, &pubKey) + pair, err := cryptoutil.NewRSAKeyPair(pubKey.Exponent, "", pubKey.Modulus) + utils.OkOrPanic(err) + password, err = pair.Encrypt(reverseStringASCII(password)) + utils.OkOrPanic(err) + allInputs["password"] = password + if isNutNeedCaptcha(ctx, loginResponseUrl, c.client) { + // 解决常规图片验证码 + captchaUrl := getNutCaptchaUrl(loginResponseUrl) + + captchaResult := ResolveOcrCaptcha(ctx, captchaUrl, c.client) + + allInputs["authcode"] = captchaResult + } else { + allInputs["authcode"] = "" + } + + // 登录提交 + loginPostResponse, err := c.client.R(). + SetFormData(allInputs). + WithContext(ctx). + Post(loginResponseUrl.String()) + + utils.OkOrPanic(err, func(err error) error { + return oops. + WithContext(ctx). + With("loginResponseUrl", loginResponseUrl). + With("allInputs", allInputs). + Wrap(err) + }) + + defer loginPostResponse.Body.Close() + + switch loginPostResponse.StatusCode() { + case 302: + handleCasLoginSuccess(ctx, loginPostResponse, schoolDetail, username, password, c.client) + case 200: + fallthrough + case 401: + doc, err := goquery.NewDocumentFromReader(loginPostResponse.Body) + utils.OkOrPanic(err, func(err error) error { + return oops. + WithContext(ctx). + With("loginResponseUrl", loginResponseUrl). + With("allInputs", allInputs). + Wrap(err) + }) + + if isCasNeedKickOut(doc) { + kickoutResponse := submitCasKickOut(ctx, loginResponseUrl.String(), doc, c.client) + handleCasLoginSuccess(ctx, kickoutResponse, schoolDetail, username, password, c.client) + return + } + + message := getCasErrorMessage(doc) + + utils.OkOrPanic(errors.NewBusinessError(503, fmt.Sprintf("今日校园登录失败: %s", message)), func(err error) error { + return oops. + WithContext(ctx). + With("loginResponseUrl", loginResponseUrl). + With("allInputs", allInputs). + With("errorMessage", message). + Wrap(errors.NewBusinessError(503, message)) + }) + } + +} +func getNutCaptchaUrl(url *url.URL) string { + return fmt.Sprintf("%s://%s/cas/kaptcha", url.Scheme, url.Host) +} +func isNutNeedCaptcha(ctx context.Context, url *url.URL, client *resty.Client) bool { + + requestURL := getNutNeedCaptchaUrl(url) + + captchaResponse, err := client.R(). + WithContext(ctx). + Get(requestURL) + + utils.OkOrPanic(oops.With(). + With("requestURL", requestURL). + WithContext(ctx). + Wrap(err)) + + defer captchaResponse.Body.Close() + + if captchaResponse.IsError() { + utils.OkOrPanic(oops.With(). + With("requestURL", requestURL). + WithContext(ctx). + Wrap(errors.NewBusinessError(503, "请求验证码失败"))) + } + + responseBytes, err := io.ReadAll(captchaResponse.Body) + utils.OkOrPanic(err) + + return strings.ToLower(strings.TrimSpace(string(responseBytes))) != "false" +} + +func getNutPubKey(url *url.URL) string { + return fmt.Sprintf("%s://%s/cas/v2/getPubKey", url.Scheme, url.Host) +} +func getNutNeedCaptchaUrl(url *url.URL) string { + return fmt.Sprintf("%s://%s/cas/v2/getKaptchaStatus", url.Scheme, url.Host) +} + +func (c CpdailyNutLogin) GetCookieJar() http.CookieJar { + return c.client.CookieJar() +} + +func (c CpdailyNutLogin) GetCookieString() string { + cookieJar := c.GetCookieJar() + serializableJar := cookieJar.(*cookiejar.PersistCookieJar) + return serializableJar.Serialize() +} + +func (c CpdailyNutLogin) GetClient() *resty.Client { + return c.client +} + +func NewNut(ctx context.Context) *CpdailyNutLogin { + return &CpdailyNutLogin{ + client: httpclient.Cpdaily.Clone(ctx), + } +} +func reverseStringASCII(s string) string { + bytes := []byte(s) + for i, j := 0, len(bytes)-1; i < j; i, j = i+1, j-1 { + bytes[i], bytes[j] = bytes[j], bytes[i] + } + return string(bytes) +} diff --git a/internal/application/cpdaily/login/ocr.go b/internal/application/cpdaily/login/ocr.go index 39d68d4..3f03f83 100644 --- a/internal/application/cpdaily/login/ocr.go +++ b/internal/application/cpdaily/login/ocr.go @@ -1,27 +1,31 @@ package login import ( + "bytes" "context" - "fmt" + "image" "io" "likedream-goframe/internal/application/recognizer/ddddocr" - "likedream-goframe/internal/framework/logger" "likedream-goframe/internal/utils" - "os" "github.com/samber/oops" - "go.uber.org/zap" "resty.dev/v3" ) func ResolveOcrCaptcha(ctx context.Context, url string, client *resty.Client) string { - codePath := DownCode2File(ctx, url, client) - img, _ := utils.ReadImg(codePath) //读取验证码图片 + byteData := DownCode2Byte(ctx, url, client) + img, err := BytesToImage(byteData) + utils.OkOrPanic(err, func(err error) error { + return oops. + With("BytesToImage", url). + WithContext(ctx). + Wrap(err) + }) data := ddddocr.AutoOCRVerification(img) return data } -func DownCode2File(ctx context.Context, url string, client *resty.Client) string { +func DownCode2Byte(ctx context.Context, url string, client *resty.Client) []byte { res, err := client.R(). WithContext(ctx). Get(url) @@ -32,23 +36,21 @@ func DownCode2File(ctx context.Context, url string, client *resty.Client) string Wrap(err) }) defer res.Body.Close() - - codeFileName := "code" + utils.GenerateRandomString(16) //生成验证码文件名称 - codeFileName += ".png" - utils.PathExistForCreate("./assets/code/") //检测是否存在路径,如果不存在则创建 - filepath := fmt.Sprintf("./assets/code/%s", codeFileName) - file, err := os.Create(filepath) - if err != nil { - logger.Logger.Error("生成验证码失败", zap.Error(err)) - return "" - } - - _, err = io.Copy(file, res.Body) - if err != nil { - logger.Logger.Error("生成验证码失败", zap.Error(err)) - return "" - } - - file.Close() - return filepath + all, err := io.ReadAll(res.Body) + utils.OkOrPanic(err, func(err error) error { + return oops. + With("captchaUrl", url). + WithContext(ctx). + Wrap(err) + }) + return all +} + +// 通用解码函数,自动检测格式 +func BytesToImage(imgBytes []byte) (image.Image, error) { + img, _, err := image.Decode(bytes.NewReader(imgBytes)) + if err != nil { + return nil, err + } + return img, nil } diff --git a/internal/application/cpdaily/taskhelper/sign.go b/internal/application/cpdaily/taskhelper/sign.go index 02b4c8b..f48268a 100644 --- a/internal/application/cpdaily/taskhelper/sign.go +++ b/internal/application/cpdaily/taskhelper/sign.go @@ -11,7 +11,7 @@ import ( "github.com/gogf/gf/v2/container/gvar" ) -const submitSignSalt = "HashSalt" // 请根据实际情况替换为真实盐值 +const submitSignSalt = "hru89rwr87Nthifa" // 请根据实际情况替换为真实盐值 func GetSubmitSign(form map[string]*gvar.Var) string { // 按照指定顺序构建哈希数据 diff --git a/internal/utils/file.go b/internal/utils/file.go index ed13df3..63c7ad4 100644 --- a/internal/utils/file.go +++ b/internal/utils/file.go @@ -4,6 +4,7 @@ import ( "fmt" "image" "image/png" + "likedream-goframe/internal/framework/logger" "os" ) @@ -13,10 +14,11 @@ func ReadImg(imgFile string) (image.Image, error) { if err != nil { return nil, err } - img, err := png.Decode(f) + img, s, err := image.Decode(f) if err != nil { return nil, err } + logger.Logger.Info(s) f.Close() return img, nil }