method.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package login
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "fmt"
  6. "git.listensoft.net/tool/jspkit/common"
  7. "git.listensoft.net/tool/jspkit/common/lxhttp"
  8. "git.listensoft.net/tool/jspkit/common/models"
  9. "git.listensoft.net/tool/jspkit/logger"
  10. "git.listensoft.net/tool/jspkit/taxerr"
  11. "github.com/go-rod/rod"
  12. "github.com/go-rod/rod/lib/proto"
  13. "github.com/go-rod/rod/lib/utils"
  14. "github.com/tidwall/gjson"
  15. "net/http"
  16. "net/url"
  17. "strings"
  18. "time"
  19. )
  20. // MakeLoginData 生成登录信息
  21. func MakeLoginData(ctx context.Context, info models.CompanyInfo) (jsonData map[string]interface{}) {
  22. loginMethod := "QRCODE"
  23. TaxNo := info.TaxNo
  24. if info.Dlfs == "代理登录" {
  25. loginMethod = "MOBILE"
  26. }
  27. website := "etax"
  28. if ctxValue := ctx.Value("website"); ctxValue != nil {
  29. if websiteStr, ok := ctxValue.(string); ok {
  30. website = websiteStr
  31. }
  32. }
  33. // 拆分登陆方式
  34. switch info.Area {
  35. case "hubei", "guangdong", "zhejiang", "tianjin":
  36. if info.Dlfs == "新版登录" {
  37. loginMethod = "ACCOUNT"
  38. }
  39. if info.Dlfs == "代理登录" && (info.Area == "guangdong" || info.Area == "zhejiang" || info.Area == "tianjin") {
  40. loginMethod = "ACCOUNT"
  41. }
  42. default:
  43. if info.Dlfs == "新版登录" {
  44. loginMethod = "QRCODE"
  45. }
  46. }
  47. changeCreditCode := ""
  48. loginType := "QIYE"
  49. if info.Dlfs == "代理登录" {
  50. changeCreditCode = info.TaxNo
  51. info.TaxNo = info.IdNo
  52. loginType = "DAILI"
  53. TaxNo = info.IdNo
  54. }
  55. jsonData = map[string]interface{}{
  56. "userInfo": map[string]string{
  57. "ComName": info.ComName,
  58. "Name": info.Area + ".pro",
  59. "CreditCode": TaxNo,
  60. "Account": info.Tel,
  61. "Password": info.Zzrmm,
  62. "dailiCreditCode": "",
  63. "changeCreditCode": changeCreditCode,
  64. },
  65. "areaName": info.Area,
  66. "loginMethod": loginMethod,
  67. "loginType": loginType,
  68. "website": website,
  69. "source": "taxRobot",
  70. //"proxies": proxies,
  71. }
  72. return
  73. }
  74. // PostLoin 登录函数
  75. func PostLoin(jsonR []byte, headder map[string]string, info models.CompanyInfo) (response []byte, err error) {
  76. f := 0
  77. //begin:
  78. //logger.Info(string(jsonR))
  79. c := lxhttp.NewHttpClient() //http://dppt.jsptax.com:81
  80. if info.Dlfs == "代理登录" {
  81. tr := &http.Transport{
  82. TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //忽略证书校验
  83. }
  84. c = &http.Client{
  85. Timeout: time.Duration(400 * time.Second),
  86. Transport: tr,
  87. }
  88. }
  89. response, err = lxhttp.PostByteReader(c, ETaxServe+"/api/login", jsonR, headder, nil)
  90. if err != nil {
  91. logger.Error(err.Error())
  92. if f < 6 {
  93. utils.Sleep(5)
  94. f++
  95. //goto begin
  96. }
  97. return response, taxerr.NewWebStuckTitle(info.Cscsts)
  98. }
  99. if strings.Contains(string(response), "Sorry, the page you are looking for is currently unavailable") || strings.Contains(string(response), "二维码已失效") ||
  100. strings.Contains(string(response), "ReadTimeoutError") || strings.Contains(string(response), "ProtocolError") {
  101. if f <= 3 {
  102. f++
  103. //goto begin
  104. }
  105. return nil, taxerr.New("新版税局登陆超时")
  106. }
  107. // 登录繁忙等30s
  108. if strings.Contains(string(response), "税局服务繁忙,请5分钟后重试") {
  109. utils.Sleep(30)
  110. if f <= 3 {
  111. f++
  112. //goto begin
  113. }
  114. }
  115. if (gjson.GetBytes(response, "msg").String() != "" && gjson.GetBytes(response, "msg").String() != "[登录成功~]") ||
  116. (gjson.GetBytes(response, "status").String() != "ok") {
  117. Str := gjson.GetBytes(response, "error").String()
  118. if Str == "" {
  119. // {"status":"false","msg":"[切换身份失败, 不存在用户91370203MA3RCTAU0X~]"}
  120. // {"status":"false","msg":"[切换身份失败, 连续认证错误次数过多,您的账号已被锁定。建议您直接使用“忘记密码”修改密码后重新登录或等待次日零时自动解锁。~]"}
  121. Str = gjson.GetBytes(response, "msg").String()
  122. }
  123. if Str == "" {
  124. Str = "新版税局登陆超时2"
  125. }
  126. if strings.Contains(Str, `请调用发送验证码`) && info.Dlfs == "新版登录" {
  127. common.DeleteTpassCookie(info)
  128. }
  129. if strings.Contains(Str, `请调用发送验证码`) && info.Dlfs == "代理登录" {
  130. err = taxerr.NewUserV3(`代理登录已掉线`, "请保证设备或app在线后重新发起任务")
  131. return
  132. }
  133. // 税局登录失败['bool' object is not subscriptable] 这个错误直接返回连续认证错误次数过多
  134. if strings.Contains(Str, `税局登录失败['bool' object is not subscriptable]`) {
  135. err = taxerr.FormatLoginError("税局登录失败[连续认证错误次数过多,您的账号已被锁定。建议您直接使用“忘记密码”修改密码后重新登录或等待次日零时自动解锁。]")
  136. return
  137. }
  138. err = taxerr.FormatLoginError(Str)
  139. return
  140. }
  141. return
  142. }
  143. func RsCookie(url string) (ck []*http.Cookie, uri string) {
  144. return nil, url
  145. if lxhttp.NeedRsvmp(url) {
  146. ck, _ = lxhttp.Rsvmp(url)
  147. return ck, url
  148. }
  149. return nil, url
  150. }
  151. // RefreshCookieBase 刷新增值税cookie和财报cookie
  152. func refreshCookieBase(client *http.Client, area, BaseIndex, api, new_key16, token string) {
  153. f := 0
  154. begin:
  155. headers := map[string]string{
  156. "Accept-Encoding": "gzip, deflate, br, zstd",
  157. "Accept-Language": "zh-CN,zh;q=0.9",
  158. "Accept": "application/json, text/plain, */*",
  159. "Content-Type": "application/json",
  160. "deviceIdentyNo": "740qhjjFG7xSNQoCFtSHA7AMzikTKeJ5",
  161. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
  162. "X-TICKET-ID": "null",
  163. "X-NATURE-IP": "",
  164. "X-SM4-INFO": "0",
  165. "X-TEMP-INFO": "null",
  166. "hUid": "",
  167. "X-APP-CLIENTID": "",
  168. "X-LANG-ID": "null",
  169. "Authorization": token,
  170. }
  171. logger.Info("埋点1")
  172. rst := lxhttp.Get_etax_clientId_redirectUri(client, api, RsCookie)
  173. logger.Info("埋点2")
  174. if rst == nil {
  175. return
  176. }
  177. logger.Info("埋点3")
  178. client_id := rst["client_id"].(string)
  179. redirect_uri := rst["redirect_uri"].(string)
  180. redirect_uri, _ = url.QueryUnescape(redirect_uri)
  181. code := lxhttp.VerifyLogin(client, area, BaseIndex, client_id, redirect_uri, new_key16, headers, RsCookie)
  182. logger.Info("埋点4")
  183. queryParams := url.Values{}
  184. queryParams.Add("code", code)
  185. if !strings.Contains(api, "invoice-query/invoice-query") {
  186. queryParams.Add("state", rst["state"].(string))
  187. }
  188. queryParams.Add("response_type", rst["response_type"].(string))
  189. hasQueryParams := strings.Contains(redirect_uri, "?")
  190. var finalRedirectURI string
  191. if hasQueryParams {
  192. finalRedirectURI = fmt.Sprintf("%s&%s", redirect_uri, queryParams.Encode())
  193. } else {
  194. finalRedirectURI = fmt.Sprintf("%s?%s", redirect_uri, queryParams.Encode())
  195. }
  196. fmt.Println("刷新cookie-uri:", finalRedirectURI)
  197. res, err := lxhttp.GET(client, finalRedirectURI, map[string]string{}, headers)
  198. if err != nil {
  199. _ = rod.Try(func() {
  200. logger.Info("finalRedirectURI失败:" + string(res))
  201. logger.Info("finalRedirectURI失败:" + err.Error())
  202. })
  203. if strings.Contains(BaseIndex, "neimeng") && f < 7 {
  204. f++
  205. goto begin
  206. }
  207. }
  208. fmt.Println(string(res))
  209. return
  210. }
  211. // RefreshCookieForAfterLogin RefreshCookie 主函数-对外开放 可以刷新两个cookie
  212. func RefreshCookieForAfterLogin(cookies map[string]string, area, BaseIndex, new_key16, token string, cwbb bool) (client *http.Client) {
  213. client = lxhttp.NewHttpClientForNoRedirects("", "")
  214. var cks []*http.Cookie
  215. for k, v := range cookies {
  216. cks = append(cks, &http.Cookie{
  217. Name: k,
  218. Value: v,
  219. })
  220. }
  221. u, _ := url.Parse(BaseIndex)
  222. client.Jar.SetCookies(u, cks)
  223. uri := BaseIndex + `/szc/szzh/sbss/ssmx/public/v1/checkLoginState`
  224. if !cwbb {
  225. uri = BaseIndex + "/szc/szzh/sjswszzh/sy/redirect?pageName=zhgl"
  226. }
  227. err := rod.Try(func() {
  228. refreshCookieBase(client, area, BaseIndex, uri, new_key16, token)
  229. })
  230. if err != nil {
  231. logger.Info(err.Error())
  232. return nil
  233. }
  234. return client
  235. }
  236. // RefreshCookieForAfterLoginRod rod使用替代afterlogin
  237. func RefreshCookieForAfterLoginRod(page *rod.Page, proxy, proxyAuth, area, BaseIndex string, cwbb bool) (client *http.Client, err error) {
  238. Tpassuri := fmt.Sprintf(`https://tpass.%s.chinatax.gov.cn:8443/#/identitySwitch/enterprise`, area)
  239. client = lxhttp.NewHttpClientForNoRedirects(proxy, proxyAuth)
  240. cookies := page.Browser().MustGetCookies()
  241. var cookiesArr []*http.Cookie
  242. for _, v := range cookies {
  243. var cookie http.Cookie
  244. cookie.Name = v.Name
  245. cookie.Value = v.Value
  246. cookie.Path = v.Path
  247. cookie.Domain = v.Domain
  248. cookiesArr = append(cookiesArr, &cookie)
  249. }
  250. u, _ := url.Parse(BaseIndex)
  251. client.Jar.SetCookies(u, cookiesArr)
  252. new_key16, token, err := GetTpassToken(page, Tpassuri)
  253. if err != nil {
  254. return
  255. }
  256. logger.Info("GetTpassToken完成")
  257. Api := BaseIndex + `/szc/szzh/sbss/ssmx/public/v1/checkLoginState`
  258. if !cwbb {
  259. Api = BaseIndex + "/szc/szzh/sjswszzh/sy/redirect?pageName=zhgl"
  260. }
  261. if area == "shanxi" {
  262. Api = `https://etax.shanxi.chinatax.gov.cn:8443/szc/szzh/sjswszzh/spHandler?cdlj=/szzh/szzh/`
  263. }
  264. err = rod.Try(func() {
  265. logger.Info("开始refreshCookieBase")
  266. refreshCookieBase(client, area, BaseIndex, Api, new_key16, token)
  267. logger.Info("结束refreshCookieBase")
  268. })
  269. if err != nil {
  270. logger.Info(err.Error())
  271. }
  272. return client, err
  273. }
  274. // RefreshCookieForAfterLogin RefreshCookie 主函数-对外开放 可以刷新两个cookie
  275. func RefreshDppt(page *rod.Page, area string) {
  276. e := rod.Try(func() {
  277. BaseIndex := GetBaseUri(area)
  278. client := lxhttp.NewHttpClientForNoRedirects("", "")
  279. {
  280. var cks []*http.Cookie
  281. for _, v := range page.Browser().MustGetCookies() {
  282. cks = append(cks, &http.Cookie{
  283. Name: v.Name,
  284. Value: v.Value,
  285. })
  286. }
  287. u, _ := url.Parse(strings.ReplaceAll(BaseIndex, "etax", "dppt"))
  288. client.Jar.SetCookies(u, cks)
  289. u, _ = url.Parse(BaseIndex)
  290. client.Jar.SetCookies(u, cks)
  291. }
  292. TpassUri := fmt.Sprintf(`https://tpass.%s.chinatax.gov.cn:8443/#/identitySwitch/enterprise`, area)
  293. new_key16, token, _ := GetTpassToken(page, TpassUri)
  294. if new_key16 == "" {
  295. return
  296. }
  297. uri := strings.ReplaceAll(GetBaseUri(area), "etax", "dppt") + "/szzhzz/spHandler?cdlj=third-menu/invoice-query/invoice-query"
  298. refreshCookieBase(client, area, BaseIndex, uri, new_key16, token)
  299. var rodCookies []*proto.NetworkCookieParam
  300. u, _ := url.Parse(BaseIndex)
  301. for _, v := range client.Jar.Cookies(u) {
  302. rodCookies = append(rodCookies,
  303. &proto.NetworkCookieParam{
  304. Name: v.Name,
  305. Value: v.Value,
  306. Domain: ".chinatax.gov.cn",
  307. Path: "/",
  308. },
  309. )
  310. }
  311. logger.Info("xxxx4")
  312. _ = page.Browser().SetCookies(rodCookies)
  313. })
  314. if e != nil {
  315. logger.Info(e.Error())
  316. }
  317. return
  318. }
  319. func GetTpassToken(page *rod.Page, TpassUrl string) (string, string, error) {
  320. var new_key16, token string
  321. err := rod.Try(func() {
  322. home := page.MustInfo().URL
  323. logger.Info(home)
  324. cookies := page.Browser().MustGetCookies()
  325. Ck := map[string]string{}
  326. for _, cookie := range cookies {
  327. Ck[cookie.Name] = cookie.Value
  328. }
  329. // 避免进不去
  330. for range "..." {
  331. page.MustNavigate(TpassUrl)
  332. utils.Sleep(2) // 加校验 //span[text()="身份切换"]
  333. page.MustWaitLoad()
  334. if common.MustHasXV(page, `//span[text()="身份切换"]`) {
  335. break
  336. } else {
  337. utils.Sleep(1.5)
  338. }
  339. }
  340. if !common.MustHasXV(page, `//span[text()="身份切换"]`) {
  341. panic(taxerr.New("获取企业所得税超时,系统将于30分钟后重试(可在\"通用设置\"关闭)"))
  342. }
  343. _ = rod.Try(func() {
  344. new_key16 = page.MustEval(`()=>localStorage.getItem('new_key16')`).String()
  345. })
  346. _ = rod.Try(func() {
  347. token = page.MustEval(`()=>localStorage.getItem('token')`).String()
  348. })
  349. logger.Info("New_key16:" + new_key16)
  350. logger.Info("Token:" + token)
  351. page.Navigate(home)
  352. })
  353. if new_key16 == "" {
  354. err = taxerr.NewWebStuckTitle(common.InfoCscsts)
  355. }
  356. return new_key16, token, err
  357. }