ChatGptAuthServiceImpl.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package com.cyksj.service.chatgpt.impl;
  2. import cn.hutool.core.date.DateTime;
  3. import cn.hutool.core.thread.ThreadUtil;
  4. import cn.hutool.http.HttpRequest;
  5. import cn.hutool.http.HttpResponse;
  6. import cn.hutool.http.HttpUtil;
  7. import cn.hutool.http.Method;
  8. import cn.hutool.json.JSONObject;
  9. import cn.hutool.json.JSONUtil;
  10. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  11. import com.cyksj.common.exception.BusinessRuntimeException;
  12. import com.cyksj.common.util.GoogleGenerator;
  13. import com.cyksj.common.util.IoKit;
  14. import com.cyksj.dto.RedisKey;
  15. import com.cyksj.mapper.AccountMapper;
  16. import com.cyksj.model.entity.Account;
  17. import com.cyksj.redis.RedisService;
  18. import com.cyksj.service.chatgpt.ChatGptAuthService;
  19. import lombok.RequiredArgsConstructor;
  20. import lombok.extern.slf4j.Slf4j;
  21. import org.apache.commons.lang3.StringUtils;
  22. import org.springframework.stereotype.Service;
  23. import java.net.InetSocketAddress;
  24. import java.net.Proxy;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.concurrent.TimeUnit;
  29. /**
  30. * @author chan
  31. * @date 2023/6/2 3:45 PM
  32. */
  33. @Service
  34. @Slf4j
  35. @RequiredArgsConstructor
  36. public class ChatGptAuthServiceImpl implements ChatGptAuthService {
  37. private final AccountMapper accountMapper;
  38. private final RedisService redisService;
  39. String user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36";
  40. private Map<String, String> cookies = new HashMap<>();
  41. private String setCookie = "Set-Cookie";
  42. private Proxy proxy = null;
  43. private void parseSetCookie(List<String> strings) {
  44. if (strings != null && !strings.isEmpty()) {
  45. for (String string : strings) {
  46. String s = string.split(";")[0];
  47. String[] split = s.split("=");
  48. cookies.put(split[0], split[1]);
  49. }
  50. }
  51. }
  52. private String getCookie() {
  53. StringBuilder stringBuilder = new StringBuilder();
  54. for (Map.Entry<String, String> entry : cookies.entrySet()) {
  55. stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("; ");
  56. }
  57. return stringBuilder.toString();
  58. }
  59. @Override
  60. public String getRefreshToken(Account account) throws Exception {
  61. //String codeVerifier = generateCodeVerifier();
  62. //String codeChallenge = generateCodeChallenge(codeVerifier);//String codeVerifier = generateCodeVerifier();
  63. //String codeChallenge = generateCodeChallenge(codeVerifier);
  64. String result = HttpUtil.get("https://dvapi.doveproxy.net/cmapi.php?rq=distribute&user=1031494735&token=ckc1MUFURnk3bi80MXVxeUFTZUh0Zz09&auth=0&geo=us&agreement=0&timeout=10&num=1&type_ip=1&repeat=0");
  65. log.info("付费ip 请求返回 res:{}",result);
  66. JSONObject resObj = JSONUtil.parseObj(result);
  67. if (200 == resObj.getInt("errno")) {
  68. JSONObject data = resObj.getJSONObject("data");
  69. proxy = new Proxy(Proxy.Type.SOCKS,
  70. new InetSocketAddress(data.getStr("ip"), data.getInt("port")));
  71. }else {
  72. log.error("----------获取 付费IP 错误 停止循环----------");
  73. }
  74. String codeVerifier = "vNniyozytMkk-MuJrIyfYcf3oUlviwEqO0MqwhDIu1U";
  75. String codeChallenge = "bAj3s8u55ymQ_OI7_JY7dPxvREDKAl_MMr_jBC74zRQ";
  76. String url = "https://auth0.openai.com/authorize?client_id=pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh&audience=https%3A%2F%2Fapi.openai.com%2Fv1&redirect_uri=com.openai.chat%3A%2F%2Fauth0.openai.com%2Fios%2Fcom.openai.chat%2Fcallback&scope=openid%20email%20profile%20offline_access%20model.request%20model.read%20organization.read%20offline&response_type=code&code_challenge=" + codeChallenge + "&code_challenge_method=S256&prompt=login&preauth_cookie=" + getPreauthCookie();
  77. Map<String, String> headers = new HashMap<>();
  78. headers.put("User-Agent", user_agent);
  79. headers.put("Referer", "https://ios.chat.openai.com/");
  80. HttpRequest httpRequest = new HttpRequest(url);
  81. httpRequest.addHeaders(headers);
  82. httpRequest.setProxy(proxy);
  83. HttpResponse execute = httpRequest.execute();
  84. parseSetCookie(execute.headerList(setCookie));
  85. String state = execute.header("Location").split("state=")[1];
  86. String refresh_token = one(codeVerifier, state, account.getAccount(), account.getPassword());
  87. account.setGptRefreshToken(refresh_token);
  88. accountMapper.updateById(account);
  89. return refresh_token;
  90. }
  91. private String getPreauthCookie() {
  92. String body = HttpUtil.get("https://ai.fakeopen.com/auth/preauth");
  93. JSONObject res = new JSONObject(body);
  94. String preauthCookie = res.getStr("preauth_cookie");
  95. if (StringUtils.isBlank(preauthCookie)) {
  96. throw BusinessRuntimeException.getInstance("Get preauth cookie failed.");
  97. }else {
  98. return preauthCookie;
  99. }
  100. }
  101. @Override
  102. public String getAccessToken(String username) throws Exception {
  103. if (redisService.get(RedisService.key.CHAT_GPT_TOKEN_EXCEPTION_KEY.getName() + username) != null) {
  104. throw BusinessRuntimeException.getInstance("该账号登录异常.");
  105. }
  106. Account account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getAccount, username));
  107. if(account == null){
  108. throw BusinessRuntimeException.getInstance("账号不存在.");
  109. }
  110. if(StringUtils.isBlank(account.getGptRefreshToken())){
  111. if (!redisService.setNx(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username, username, RedisService.key.CHAT_GPT_TOKEN_KEY.getTimeout())) {
  112. throw BusinessRuntimeException.getInstance("正在获取直连token中...");
  113. }
  114. String refreshToken = getRefreshToken(account);
  115. if(StringUtils.isBlank(refreshToken)){
  116. redisService.del(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username);
  117. throw BusinessRuntimeException.getInstance("该账号登录异常.");
  118. }
  119. account.setGptRefreshToken(refreshToken);
  120. accountMapper.updateById(account);
  121. redisService.del(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username);
  122. return redisService.getStr(RedisKey.CHATGPT_ACCESS_TOKEN + account.getAccount());
  123. }
  124. String accessToken = redisService.getStr(RedisKey.CHATGPT_ACCESS_TOKEN + username);
  125. if (StringUtils.isBlank(accessToken)) {
  126. accessToken = getAccessTokenByRefreshToken(account.getGptRefreshToken());
  127. redisService.set(RedisKey.CHATGPT_ACCESS_TOKEN + account.getAccount(), accessToken, 1209300L);
  128. return accessToken;
  129. }else {
  130. return accessToken;
  131. }
  132. }
  133. private String one(String codeVerifier, String state, String username, String password) {
  134. String url = "https://auth0.openai.com/u/login/identifier?state=" + state;
  135. Map<String, String> headers = new HashMap<>();
  136. Map<String, Object> map = new HashMap<>();
  137. map.put("state", state);
  138. map.put("username", username);
  139. map.put("js-available", true);
  140. map.put("webauthn-available", true);
  141. map.put("is-brave", false);
  142. map.put("webauthn-platform-available", false);
  143. map.put("action", "default");
  144. headers.put("User-Agent", user_agent);
  145. headers.put("Referer", url);
  146. headers.put("Origin", "https://auth0.openai.com");
  147. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, false).cookie(getCookie()).form(map).execute();
  148. parseSetCookie(execute.headerList(setCookie));
  149. log.info("one:{}",execute.body());
  150. if (execute.getStatus() == 302) {
  151. return two(codeVerifier, state, username, password);
  152. }
  153. return null;
  154. }
  155. private String two(String codeVerifier, String state, String username, String password) {
  156. String url = "https://auth0.openai.com/u/login/password?state=" + state;
  157. Map<String, String> headers = new HashMap<>();
  158. headers.put("User-Agent", user_agent);
  159. headers.put("Referer", url);
  160. headers.put("Origin", "https://auth0.openai.com");
  161. Map<String, Object> map = new HashMap<>();
  162. map.put("state", state);
  163. map.put("username", username);
  164. map.put("password", password);
  165. map.put("action", "default");
  166. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  167. parseSetCookie(execute.headerList(setCookie));
  168. log.info("two:{}",execute.body());
  169. if (execute.getStatus() == 302) {
  170. String Location = execute.header("Location");
  171. if (Location.contains("/authorize/resume?")) {
  172. return three(codeVerifier, Location, url, username);
  173. } else {
  174. log.info("Login failed.");
  175. }
  176. }
  177. return null;
  178. }
  179. private String three(String codeVerifier, String location, String url1, String username) {
  180. String url = "https://auth0.openai.com" + location;
  181. Map<String, String> headers = new HashMap<>();
  182. headers.put("User-Agent", user_agent);
  183. headers.put("Referer", url1);
  184. HttpRequest httpRequest = new HttpRequest(url);
  185. httpRequest.headerMap(headers, true);
  186. httpRequest.method(Method.GET);
  187. httpRequest.cookie(getCookie());
  188. httpRequest.setProxy(proxy);
  189. HttpResponse execute = httpRequest.execute();
  190. parseSetCookie(execute.headerList(setCookie));
  191. log.info("three:{}",execute.body());
  192. if (execute.getStatus() == 302) {
  193. String Location = execute.header("Location");
  194. if (Location.startsWith("/u/mfa-otp-challenge?")) {
  195. Account account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getAccount,username));
  196. if (account == null) {
  197. throw BusinessRuntimeException.getInstance("账号不存在.");
  198. }
  199. if (StringUtils.isBlank(account.getApiSecret())) {
  200. throw BusinessRuntimeException.getInstance("双重验证密钥为空.");
  201. }
  202. DateTime now = DateTime.now();
  203. int second = now.second();
  204. if (second < 30 && 30 - second < 3) {
  205. ThreadUtil.sleep(30 - second + 1, TimeUnit.SECONDS);
  206. } else if (second > 30 && 60 - second < 3) {
  207. ThreadUtil.sleep(60 - second + 1, TimeUnit.SECONDS);
  208. }
  209. StringBuilder sb = new StringBuilder();
  210. long code = GoogleGenerator.getCode(account.getApiSecret(), now.getTime());
  211. sb.append(code);
  212. while (sb.length() < 6) {
  213. sb.insert(0, 0);
  214. }
  215. return four(codeVerifier, Location, code, username);
  216. } else if (Location.contains("com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?")) {
  217. return getAccessToken(codeVerifier, Location, username);
  218. } else {
  219. log.info("Login callback failed.");
  220. }
  221. }
  222. return null;
  223. }
  224. private String four(String codeVerifier, String location, long code, String username){
  225. String url = "https://auth0.openai.com" + location;
  226. Map<String, String> paramMap = HttpUtil.decodeParamMap(url, IoKit.Charsets.UTF_8.getCharset());
  227. Map<String, String> headers = new HashMap<>();
  228. headers.put("User-Agent", user_agent);
  229. headers.put("Referer",url);
  230. headers.put("Origin","https://auth0.openai.com");
  231. Map<String, Object> map = new HashMap<>();
  232. map.put("state", paramMap.get("state"));
  233. map.put("code", code);
  234. map.put("action", "default");
  235. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  236. parseSetCookie(execute.headerList(setCookie));
  237. log.info("four:{}",execute.body());
  238. if (execute.getStatus() == 302) {
  239. String Location = execute.header("Location");
  240. if (Location.contains("/authorize/resume?")) {
  241. return three(codeVerifier, Location, url, username);
  242. } else {
  243. log.info("Login failed.");
  244. throw BusinessRuntimeException.getInstance("four Login failed.");
  245. }
  246. } else if (execute.getStatus() == 400) {
  247. throw BusinessRuntimeException.getInstance("wrong MFA code.");
  248. }else {
  249. throw BusinessRuntimeException.getInstance("error login.");
  250. }
  251. }
  252. private String getAccessToken(String codeVerifier, String Location, String username) {
  253. //com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?code=jeix6iK_JWoUBuL7QUBeI_pryDHVwvnINqRFjttMfX4NK
  254. if (!Location.contains("code")) {
  255. log.info("Login code failed.");
  256. }
  257. String code = Location.split("\\?code=")[1];
  258. String url = "https://auth0.openai.com/oauth/token";
  259. Map<String, String> headers = new HashMap<>();
  260. headers.put("User-Agent", user_agent);
  261. Map<String, Object> map = new HashMap<>();
  262. map.put("redirect_uri", "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback");
  263. map.put("grant_type", "authorization_code");
  264. map.put("client_id", "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh");
  265. map.put("code", code);
  266. map.put("code_verifier", codeVerifier);
  267. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  268. /**
  269. * {
  270. * "access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL3Byb2ZpbGUiOnsiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWV9LCJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdWQiOlsiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MSIsImh0dHBzOi8vb3BlbmFpLm9wZW5haS5hdXRoMGFwcC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjg1Njc0ODA3LCJleHAiOjE2ODY4ODQ0MDcsImF6cCI6InBkbExJWDJZNzJNSWwycmhMaFRFOVZWOWJOOTA1a0JoIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBtb2RlbC5yZWFkIG1vZGVsLnJlcXVlc3Qgb3JnYW5pemF0aW9uLnJlYWQgb2ZmbGluZV9hY2Nlc3MifQ.frAW5ZylGC1DcdpCvJo_9xo9mf-QrSRfSonNVxZocr25Y-92MEt7aqWu5IRS_J6Y0o82FzbcODQ2xFjJ5B_mGAJVuLRpfSfiEFJLzIfPF2d2s39hB-g9LqfdXmIQM3-rh7hAHuh6_nu9apdLt69lIakPd9w0XqgOfACQlHiZZND-MhnOp-l_LVoX3RmSJ2QWcxviLiAsdwMZhrNK7HH5mAlL8PDZCCOqA61NPi0pBpv3WIufLpesYOmJqyMg8QGKXppc7frgwJuXuZo_cKopZjHo9NAcbB_hfyp0QJUdPMiv_u_Si2fhJVOdb8zEVki-aZlHVZ-lYET4BaBeZSBHtg",
  271. * "refresh_token":"LE_iTCK3WZfNV-RENjaA_JE8a5WkhMsEJjLKL8ZH_cpkD",
  272. * "id_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsiZ3JvdXBzIjpbXSwib3JnYW5pemF0aW9ucyI6W3siaWQiOiJvcmctMGpFYUZaQVVTNkc1VHRCaHo1YjdSVlQ2IiwiaXNfZGVmYXVsdCI6dHJ1ZSwicm9sZSI6Im93bmVyIiwidGl0bGUiOiJQZXJzb25hbCJ9XSwidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sIm5pY2tuYW1lIjoiYXVkcmV5Ym9vdGhjaGVsc2VhIiwibmFtZSI6ImF1ZHJleWJvb3RoY2hlbHNlYUBnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvOWNhM2U5NDY3OGZlODYzNWE0N2ZjOGE0NGU2ZTk3MWI_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZhdS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyMy0wNi0wMlQwMzowMDowMy4zMTZaIiwiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJhdWQiOiJwZGxMSVgyWTcyTUlsMnJoTGhURTlWVjliTjkwNWtCaCIsImlhdCI6MTY4NTY3NDgwNywiZXhwIjoxNjg1NzEwODA3LCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdXRoX3RpbWUiOjE2ODU2NzQ4MDMsInNpZCI6ImxDbEk5cnVibVYzcE5aQjNqd1JPYm5iT2toeTl3RmFRIn0.zD464ErSUS7_q-BhGksLzK5kcy9mDEzrpZxSO4cqHci09KaWSPgCvm8S2N0fF3pDFw9juCpiN8RfqnPXJG2oCCJhUiTDHzX2yux6qf5IEdNe-wwdqoD7fLUv7JsdkZS-wXIHlvYOhFg3lRuE5mqvDOXR8lDCF_WEuqftYuWVD8DijwrA8a0GybFyj-idxYoJcWFYaHae6KTai8RHnGRERf8L4R0N1rnx86YzXsXl4-ZHnkTYR7X3J66k05gKsZY_TGoejae7kXs66UWeoMu4PjtLHKrsCW98X_1cjU3oXnqi40jwylZ5GCMn_V77WRAI-Q-0lbZNesGYJy8bF0Hz4Q",
  273. * "scope":"openid profile email model.read model.request organization.read offline_access",
  274. * "expires_in":1209600,
  275. * "token_type":"Bearer"
  276. * }
  277. */
  278. if (execute.getStatus() == 200) {
  279. log.info(execute.body());
  280. JSONObject accessToken = new JSONObject(execute.body());
  281. redisService.set(RedisKey.CHATGPT_ACCESS_TOKEN + username, accessToken.getStr("access_token"),accessToken.getLong("expires_in"));
  282. return accessToken.getStr("refresh_token");
  283. }
  284. return null;
  285. }
  286. public String getAccessTokenByRefreshToken(String refreshToken){
  287. String result = HttpUtil.get("https://dvapi.doveproxy.net/cmapi.php?rq=distribute&user=1031494735&token=ckc1MUFURnk3bi80MXVxeUFTZUh0Zz09&auth=0&geo=us&agreement=0&timeout=10&num=1&type_ip=1&repeat=0");
  288. log.info("付费ip 请求返回 res:{}",result);
  289. JSONObject resObj = JSONUtil.parseObj(result);
  290. if (200 == resObj.getInt("errno")) {
  291. JSONObject data = resObj.getJSONObject("data");
  292. Proxy proxy = new Proxy(Proxy.Type.SOCKS,
  293. new InetSocketAddress(data.getStr("ip"), data.getInt("port")));
  294. JSONObject params = new JSONObject();
  295. params.putOpt("redirect_uri","com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback");
  296. params.putOpt("grant_type","refresh_token");
  297. params.putOpt("client_id","pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh");
  298. params.putOpt("refresh_token",refreshToken);
  299. HttpRequest request = HttpRequest.post("https://auth0.openai.com/oauth/token").setProxy(proxy)
  300. .body(params.toString());
  301. HttpResponse execute = request.execute();
  302. if (execute.getStatus() == 200) {
  303. JSONObject res = new JSONObject(execute.body());
  304. return res.getStr("access_token");
  305. }else {
  306. throw BusinessRuntimeException.getInstance("获取token失败.");
  307. }
  308. }else {
  309. log.error("----------获取 付费IP 错误 ----------");
  310. throw BusinessRuntimeException.getInstance("获取ip错误");
  311. }
  312. }
  313. }