ChatGptAuthServiceImpl.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. Account account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getAccount, username));
  104. if(account == null){
  105. throw BusinessRuntimeException.getInstance("账号不存在.");
  106. }
  107. if(StringUtils.isBlank(account.getGptRefreshToken())){
  108. if (!redisService.setNx(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username, username, RedisService.key.CHAT_GPT_TOKEN_KEY.getTimeout())) {
  109. throw BusinessRuntimeException.getInstance("正在获取直连token中...");
  110. }
  111. String refreshToken = getRefreshToken(account);
  112. if(StringUtils.isBlank(refreshToken)){
  113. redisService.del(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username);
  114. throw BusinessRuntimeException.getInstance("该账号登录异常.");
  115. }
  116. account.setGptRefreshToken(refreshToken);
  117. accountMapper.updateById(account);
  118. redisService.del(RedisService.key.CHAT_GPT_TOKEN_KEY.getName() + username);
  119. return redisService.getStr(RedisKey.CHATGPT_ACCESS_TOKEN + account.getAccount());
  120. }
  121. String accessToken = redisService.getStr(RedisKey.CHATGPT_ACCESS_TOKEN + username);
  122. if (StringUtils.isBlank(accessToken)) {
  123. accessToken = getAccessTokenByRefreshToken(account.getGptRefreshToken());
  124. redisService.set(RedisKey.CHATGPT_ACCESS_TOKEN + account.getAccount(), accessToken, 1209300L);
  125. return accessToken;
  126. }else {
  127. return accessToken;
  128. }
  129. }
  130. private String one(String codeVerifier, String state, String username, String password) {
  131. String url = "https://auth0.openai.com/u/login/identifier?state=" + state;
  132. Map<String, String> headers = new HashMap<>();
  133. Map<String, Object> map = new HashMap<>();
  134. map.put("state", state);
  135. map.put("username", username);
  136. map.put("js-available", true);
  137. map.put("webauthn-available", true);
  138. map.put("is-brave", false);
  139. map.put("webauthn-platform-available", false);
  140. map.put("action", "default");
  141. headers.put("User-Agent", user_agent);
  142. headers.put("Referer", url);
  143. headers.put("Origin", "https://auth0.openai.com");
  144. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, false).cookie(getCookie()).form(map).execute();
  145. parseSetCookie(execute.headerList(setCookie));
  146. log.info("one:{}",execute.body());
  147. if (execute.getStatus() == 302) {
  148. return two(codeVerifier, state, username, password);
  149. }
  150. return null;
  151. }
  152. private String two(String codeVerifier, String state, String username, String password) {
  153. String url = "https://auth0.openai.com/u/login/password?state=" + state;
  154. Map<String, String> headers = new HashMap<>();
  155. headers.put("User-Agent", user_agent);
  156. headers.put("Referer", url);
  157. headers.put("Origin", "https://auth0.openai.com");
  158. Map<String, Object> map = new HashMap<>();
  159. map.put("state", state);
  160. map.put("username", username);
  161. map.put("password", password);
  162. map.put("action", "default");
  163. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  164. parseSetCookie(execute.headerList(setCookie));
  165. log.info("two:{}",execute.body());
  166. if (execute.getStatus() == 302) {
  167. String Location = execute.header("Location");
  168. if (Location.contains("/authorize/resume?")) {
  169. return three(codeVerifier, Location, url, username);
  170. } else {
  171. log.info("Login failed.");
  172. }
  173. }
  174. return null;
  175. }
  176. private String three(String codeVerifier, String location, String url1, String username) {
  177. String url = "https://auth0.openai.com" + location;
  178. Map<String, String> headers = new HashMap<>();
  179. headers.put("User-Agent", user_agent);
  180. headers.put("Referer", url1);
  181. HttpRequest httpRequest = new HttpRequest(url);
  182. httpRequest.headerMap(headers, true);
  183. httpRequest.method(Method.GET);
  184. httpRequest.cookie(getCookie());
  185. httpRequest.setProxy(proxy);
  186. HttpResponse execute = httpRequest.execute();
  187. parseSetCookie(execute.headerList(setCookie));
  188. log.info("three:{}",execute.body());
  189. if (execute.getStatus() == 302) {
  190. String Location = execute.header("Location");
  191. if (Location.startsWith("/u/mfa-otp-challenge?")) {
  192. Account account = accountMapper.selectOne(Wrappers.lambdaQuery(Account.class).eq(Account::getAccount,username));
  193. if (account == null) {
  194. throw BusinessRuntimeException.getInstance("账号不存在.");
  195. }
  196. if (StringUtils.isBlank(account.getApiSecret())) {
  197. throw BusinessRuntimeException.getInstance("双重验证密钥为空.");
  198. }
  199. DateTime now = DateTime.now();
  200. int second = now.second();
  201. if (second < 30 && 30 - second < 3) {
  202. ThreadUtil.sleep(30 - second + 1, TimeUnit.SECONDS);
  203. } else if (second > 30 && 60 - second < 3) {
  204. ThreadUtil.sleep(60 - second + 1, TimeUnit.SECONDS);
  205. }
  206. StringBuilder sb = new StringBuilder();
  207. long code = GoogleGenerator.getCode(account.getApiSecret(), now.getTime());
  208. sb.append(code);
  209. while (sb.length() < 6) {
  210. sb.insert(0, 0);
  211. }
  212. return four(codeVerifier, Location, code, username);
  213. } else if (Location.contains("com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?")) {
  214. return getAccessToken(codeVerifier, Location, username);
  215. } else {
  216. log.info("Login callback failed.");
  217. }
  218. }
  219. return null;
  220. }
  221. private String four(String codeVerifier, String location, long code, String username){
  222. String url = "https://auth0.openai.com" + location;
  223. Map<String, String> paramMap = HttpUtil.decodeParamMap(url, IoKit.Charsets.UTF_8.getCharset());
  224. Map<String, String> headers = new HashMap<>();
  225. headers.put("User-Agent", user_agent);
  226. headers.put("Referer",url);
  227. headers.put("Origin","https://auth0.openai.com");
  228. Map<String, Object> map = new HashMap<>();
  229. map.put("state", paramMap.get("state"));
  230. map.put("code", code);
  231. map.put("action", "default");
  232. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  233. parseSetCookie(execute.headerList(setCookie));
  234. log.info("four:{}",execute.body());
  235. if (execute.getStatus() == 302) {
  236. String Location = execute.header("Location");
  237. if (Location.contains("/authorize/resume?")) {
  238. return three(codeVerifier, Location, url, username);
  239. } else {
  240. log.info("Login failed.");
  241. throw BusinessRuntimeException.getInstance("four Login failed.");
  242. }
  243. } else if (execute.getStatus() == 400) {
  244. throw BusinessRuntimeException.getInstance("wrong MFA code.");
  245. }else {
  246. throw BusinessRuntimeException.getInstance("error login.");
  247. }
  248. }
  249. private String getAccessToken(String codeVerifier, String Location, String username) {
  250. //com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?code=jeix6iK_JWoUBuL7QUBeI_pryDHVwvnINqRFjttMfX4NK
  251. if (!Location.contains("code")) {
  252. log.info("Login code failed.");
  253. }
  254. String code = Location.split("\\?code=")[1];
  255. String url = "https://auth0.openai.com/oauth/token";
  256. Map<String, String> headers = new HashMap<>();
  257. headers.put("User-Agent", user_agent);
  258. Map<String, Object> map = new HashMap<>();
  259. map.put("redirect_uri", "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback");
  260. map.put("grant_type", "authorization_code");
  261. map.put("client_id", "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh");
  262. map.put("code", code);
  263. map.put("code_verifier", codeVerifier);
  264. HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
  265. /**
  266. * {
  267. * "access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL3Byb2ZpbGUiOnsiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWV9LCJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdWQiOlsiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MSIsImh0dHBzOi8vb3BlbmFpLm9wZW5haS5hdXRoMGFwcC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjg1Njc0ODA3LCJleHAiOjE2ODY4ODQ0MDcsImF6cCI6InBkbExJWDJZNzJNSWwycmhMaFRFOVZWOWJOOTA1a0JoIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBtb2RlbC5yZWFkIG1vZGVsLnJlcXVlc3Qgb3JnYW5pemF0aW9uLnJlYWQgb2ZmbGluZV9hY2Nlc3MifQ.frAW5ZylGC1DcdpCvJo_9xo9mf-QrSRfSonNVxZocr25Y-92MEt7aqWu5IRS_J6Y0o82FzbcODQ2xFjJ5B_mGAJVuLRpfSfiEFJLzIfPF2d2s39hB-g9LqfdXmIQM3-rh7hAHuh6_nu9apdLt69lIakPd9w0XqgOfACQlHiZZND-MhnOp-l_LVoX3RmSJ2QWcxviLiAsdwMZhrNK7HH5mAlL8PDZCCOqA61NPi0pBpv3WIufLpesYOmJqyMg8QGKXppc7frgwJuXuZo_cKopZjHo9NAcbB_hfyp0QJUdPMiv_u_Si2fhJVOdb8zEVki-aZlHVZ-lYET4BaBeZSBHtg",
  268. * "refresh_token":"LE_iTCK3WZfNV-RENjaA_JE8a5WkhMsEJjLKL8ZH_cpkD",
  269. * "id_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsiZ3JvdXBzIjpbXSwib3JnYW5pemF0aW9ucyI6W3siaWQiOiJvcmctMGpFYUZaQVVTNkc1VHRCaHo1YjdSVlQ2IiwiaXNfZGVmYXVsdCI6dHJ1ZSwicm9sZSI6Im93bmVyIiwidGl0bGUiOiJQZXJzb25hbCJ9XSwidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sIm5pY2tuYW1lIjoiYXVkcmV5Ym9vdGhjaGVsc2VhIiwibmFtZSI6ImF1ZHJleWJvb3RoY2hlbHNlYUBnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvOWNhM2U5NDY3OGZlODYzNWE0N2ZjOGE0NGU2ZTk3MWI_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZhdS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyMy0wNi0wMlQwMzowMDowMy4zMTZaIiwiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJhdWQiOiJwZGxMSVgyWTcyTUlsMnJoTGhURTlWVjliTjkwNWtCaCIsImlhdCI6MTY4NTY3NDgwNywiZXhwIjoxNjg1NzEwODA3LCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdXRoX3RpbWUiOjE2ODU2NzQ4MDMsInNpZCI6ImxDbEk5cnVibVYzcE5aQjNqd1JPYm5iT2toeTl3RmFRIn0.zD464ErSUS7_q-BhGksLzK5kcy9mDEzrpZxSO4cqHci09KaWSPgCvm8S2N0fF3pDFw9juCpiN8RfqnPXJG2oCCJhUiTDHzX2yux6qf5IEdNe-wwdqoD7fLUv7JsdkZS-wXIHlvYOhFg3lRuE5mqvDOXR8lDCF_WEuqftYuWVD8DijwrA8a0GybFyj-idxYoJcWFYaHae6KTai8RHnGRERf8L4R0N1rnx86YzXsXl4-ZHnkTYR7X3J66k05gKsZY_TGoejae7kXs66UWeoMu4PjtLHKrsCW98X_1cjU3oXnqi40jwylZ5GCMn_V77WRAI-Q-0lbZNesGYJy8bF0Hz4Q",
  270. * "scope":"openid profile email model.read model.request organization.read offline_access",
  271. * "expires_in":1209600,
  272. * "token_type":"Bearer"
  273. * }
  274. */
  275. if (execute.getStatus() == 200) {
  276. log.info(execute.body());
  277. JSONObject accessToken = new JSONObject(execute.body());
  278. redisService.set(RedisKey.CHATGPT_ACCESS_TOKEN + username, accessToken.getStr("access_token"),accessToken.getLong("expires_in"));
  279. return accessToken.getStr("refresh_token");
  280. }
  281. return null;
  282. }
  283. public String getAccessTokenByRefreshToken(String refreshToken){
  284. 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");
  285. log.info("付费ip 请求返回 res:{}",result);
  286. JSONObject resObj = JSONUtil.parseObj(result);
  287. if (200 == resObj.getInt("errno")) {
  288. JSONObject data = resObj.getJSONObject("data");
  289. Proxy proxy = new Proxy(Proxy.Type.SOCKS,
  290. new InetSocketAddress(data.getStr("ip"), data.getInt("port")));
  291. JSONObject params = new JSONObject();
  292. params.putOpt("redirect_uri","com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback");
  293. params.putOpt("grant_type","refresh_token");
  294. params.putOpt("client_id","pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh");
  295. params.putOpt("refresh_token",refreshToken);
  296. HttpRequest request = HttpRequest.post("https://auth0.openai.com/oauth/token").setProxy(proxy)
  297. .body(params.toString());
  298. HttpResponse execute = request.execute();
  299. if (execute.getStatus() == 200) {
  300. JSONObject res = new JSONObject(execute.body());
  301. return res.getStr("access_token");
  302. }else {
  303. throw BusinessRuntimeException.getInstance("获取token失败.");
  304. }
  305. }else {
  306. log.error("----------获取 付费IP 错误 ----------");
  307. throw BusinessRuntimeException.getInstance("获取ip错误");
  308. }
  309. }
  310. }