|
@@ -0,0 +1,282 @@
|
|
|
|
|
+package com.cyksj.service.chatgpt.impl;
|
|
|
|
|
+
|
|
|
|
|
+import cn.hutool.core.date.DateTime;
|
|
|
|
|
+import cn.hutool.core.thread.ThreadUtil;
|
|
|
|
|
+import cn.hutool.http.HttpRequest;
|
|
|
|
|
+import cn.hutool.http.HttpResponse;
|
|
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
|
|
+import cn.hutool.http.Method;
|
|
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
|
|
+import com.cyksj.common.exception.BusinessRuntimeException;
|
|
|
|
|
+import com.cyksj.common.util.GoogleGenerator;
|
|
|
|
|
+import com.cyksj.common.util.IoKit;
|
|
|
|
|
+import com.cyksj.dto.RedisKey;
|
|
|
|
|
+import com.cyksj.mapper.AccountMapper;
|
|
|
|
|
+import com.cyksj.model.entity.Account;
|
|
|
|
|
+import com.cyksj.redis.RedisService;
|
|
|
|
|
+import com.cyksj.service.chatgpt.ChatGptAuthService;
|
|
|
|
|
+import com.ejlchina.searcher.BeanSearcher;
|
|
|
|
|
+import com.ejlchina.searcher.util.MapUtils;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import java.net.InetSocketAddress;
|
|
|
|
|
+import java.net.Proxy;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @author chan
|
|
|
|
|
+ * @date 2023/6/2 3:45 PM
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class ChatGptAuthServiceImpl implements ChatGptAuthService {
|
|
|
|
|
+
|
|
|
|
|
+ private final AccountMapper accountMapper;
|
|
|
|
|
+
|
|
|
|
|
+ private final BeanSearcher beanSearcher;
|
|
|
|
|
+
|
|
|
|
|
+ private final RedisService redisService;
|
|
|
|
|
+
|
|
|
|
|
+ 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";
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, String> cookies = new HashMap<>();
|
|
|
|
|
+ private String setCookie = "Set-Cookie";
|
|
|
|
|
+
|
|
|
|
|
+ private Proxy proxy = null;
|
|
|
|
|
+
|
|
|
|
|
+ private void parseSetCookie(List<String> strings) {
|
|
|
|
|
+ if (strings != null && !strings.isEmpty()) {
|
|
|
|
|
+ for (String string : strings) {
|
|
|
|
|
+ String s = string.split(";")[0];
|
|
|
|
|
+ String[] split = s.split("=");
|
|
|
|
|
+ cookies.put(split[0], split[1]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String getCookie() {
|
|
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
|
+ for (Map.Entry<String, String> entry : cookies.entrySet()) {
|
|
|
|
|
+ stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("; ");
|
|
|
|
|
+ }
|
|
|
|
|
+ return stringBuilder.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String getRefreshToken(Account account) throws Exception {
|
|
|
|
|
+ //String codeVerifier = generateCodeVerifier();
|
|
|
|
|
+ //String codeChallenge = generateCodeChallenge(codeVerifier);//String codeVerifier = generateCodeVerifier();
|
|
|
|
|
+ //String codeChallenge = generateCodeChallenge(codeVerifier);
|
|
|
|
|
+ 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");
|
|
|
|
|
+ log.info("付费ip 请求返回 res:{}",result);
|
|
|
|
|
+ JSONObject resObj = JSONUtil.parseObj(result);
|
|
|
|
|
+ if (200 == resObj.getInt("errno")) {
|
|
|
|
|
+ JSONObject data = resObj.getJSONObject("data");
|
|
|
|
|
+
|
|
|
|
|
+ proxy = new Proxy(Proxy.Type.SOCKS,
|
|
|
|
|
+ new InetSocketAddress(data.getStr("ip"), data.getInt("port")));
|
|
|
|
|
+ }else {
|
|
|
|
|
+ log.error("----------获取 付费IP 错误 停止循环----------");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String codeVerifier = "vNniyozytMkk-MuJrIyfYcf3oUlviwEqO0MqwhDIu1U";
|
|
|
|
|
+ String codeChallenge = "bAj3s8u55ymQ_OI7_JY7dPxvREDKAl_MMr_jBC74zRQ";
|
|
|
|
|
+
|
|
|
|
|
+ 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";
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+ headers.put("Referer", "https://ios.chat.openai.com/");
|
|
|
|
|
+ HttpRequest httpRequest = new HttpRequest(url);
|
|
|
|
|
+ httpRequest.addHeaders(headers);
|
|
|
|
|
+ httpRequest.setProxy(proxy);
|
|
|
|
|
+ HttpResponse execute = httpRequest.execute();
|
|
|
|
|
+ parseSetCookie(execute.headerList(setCookie));
|
|
|
|
|
+ String state = execute.header("Location").split("state=")[1];
|
|
|
|
|
+ String refresh_token = one(codeVerifier, state, account.getAccount(), account.getPassword());
|
|
|
|
|
+ account.setGptRefreshToken(refresh_token);
|
|
|
|
|
+ accountMapper.updateById(account);
|
|
|
|
|
+ return refresh_token;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String one(String codeVerifier, String state, String username, String password) {
|
|
|
|
|
+ String url = "https://auth0.openai.com/u/login/identifier?state=" + state;
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
|
|
+ map.put("state", state);
|
|
|
|
|
+ map.put("username", "audreyboothchelsea@gmail.com");
|
|
|
|
|
+ map.put("js-available", true);
|
|
|
|
|
+ map.put("webauthn-available", true);
|
|
|
|
|
+ map.put("is-brave", false);
|
|
|
|
|
+ map.put("webauthn-platform-available", false);
|
|
|
|
|
+ map.put("action", "default");
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+ headers.put("Referer", url);
|
|
|
|
|
+ headers.put("Origin", "https://auth0.openai.com");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, false).cookie(getCookie()).form(map).execute();
|
|
|
|
|
+ parseSetCookie(execute.headerList(setCookie));
|
|
|
|
|
+ log.info(execute.body());
|
|
|
|
|
+ if (execute.getStatus() == 302) {
|
|
|
|
|
+ return two(codeVerifier, state, username, password);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String two(String codeVerifier, String state, String username, String password) {
|
|
|
|
|
+ String url = "https://auth0.openai.com/u/login/password?state=" + state;
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+ headers.put("Referer", url);
|
|
|
|
|
+ headers.put("Origin", "https://auth0.openai.com");
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
|
|
+ map.put("state", state);
|
|
|
|
|
+ map.put("username", username);
|
|
|
|
|
+ map.put("password", password);
|
|
|
|
|
+ map.put("action", "default");
|
|
|
|
|
+ HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
|
|
|
|
|
+ parseSetCookie(execute.headerList(setCookie));
|
|
|
|
|
+ if (execute.getStatus() == 302) {
|
|
|
|
|
+ String Location = execute.header("Location");
|
|
|
|
|
+ if (Location.contains("/authorize/resume?")) {
|
|
|
|
|
+ return three(codeVerifier, Location, url, username);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("Login failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String three(String codeVerifier, String location, String url1, String username) {
|
|
|
|
|
+ String url = "https://auth0.openai.com" + location;
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+ headers.put("Referer", url1);
|
|
|
|
|
+
|
|
|
|
|
+ HttpRequest httpRequest = new HttpRequest(url);
|
|
|
|
|
+ httpRequest.headerMap(headers, true);
|
|
|
|
|
+ httpRequest.method(Method.GET);
|
|
|
|
|
+ httpRequest.cookie(getCookie());
|
|
|
|
|
+ httpRequest.setProxy(proxy);
|
|
|
|
|
+ HttpResponse execute = httpRequest.execute();
|
|
|
|
|
+ if (execute.getStatus() == 302) {
|
|
|
|
|
+ String Location = execute.header("Location");
|
|
|
|
|
+ if (Location.startsWith("/u/mfa-otp-challenge?")) {
|
|
|
|
|
+ Account account = beanSearcher.searchFirst(Account.class, MapUtils.builder()
|
|
|
|
|
+ .field(Account::getAccount, username).build());
|
|
|
|
|
+ if (account == null) {
|
|
|
|
|
+ throw BusinessRuntimeException.getInstance("账号不存在.");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.isBlank(account.getApiSecret())) {
|
|
|
|
|
+ throw BusinessRuntimeException.getInstance("双重验证密钥为空.");
|
|
|
|
|
+ }
|
|
|
|
|
+ DateTime now = DateTime.now();
|
|
|
|
|
+ int second = now.second();
|
|
|
|
|
+ if (second < 30 && 30 - second < 3) {
|
|
|
|
|
+ ThreadUtil.sleep(30 - second + 1, TimeUnit.SECONDS);
|
|
|
|
|
+ } else if (second > 30 && 60 - second < 3) {
|
|
|
|
|
+ ThreadUtil.sleep(60 - second + 1, TimeUnit.SECONDS);
|
|
|
|
|
+ }
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ long code = GoogleGenerator.getCode(account.getApiSecret(), now.getTime());
|
|
|
|
|
+ sb.append(code);
|
|
|
|
|
+ while (sb.length() < 6) {
|
|
|
|
|
+ sb.insert(0, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ four(codeVerifier, location, code, username);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Location.contains("com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?")) {
|
|
|
|
|
+ return getAccessToken(codeVerifier, Location, username);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("Login callback failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void four(String codeVerifier, String location, long code, String username){
|
|
|
|
|
+ String url = "https://auth0.openai.com" + location;
|
|
|
|
|
+ Map<String, String> paramMap = HttpUtil.decodeParamMap(url, IoKit.Charsets.UTF_8.getCharset());
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+ headers.put("Referer",url);
|
|
|
|
|
+ headers.put("Origin","https://auth0.openai.com");
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
|
|
+ map.put("state", paramMap.get("state"));
|
|
|
|
|
+ map.put("code", code);
|
|
|
|
|
+ map.put("action", "default");
|
|
|
|
|
+
|
|
|
|
|
+ HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
|
|
|
|
|
+ parseSetCookie(execute.headerList(setCookie));
|
|
|
|
|
+
|
|
|
|
|
+ if (execute.getStatus() == 302) {
|
|
|
|
|
+ String Location = execute.header("Location");
|
|
|
|
|
+ if (Location.contains("/authorize/resume?")) {
|
|
|
|
|
+ three(codeVerifier, Location, url, username);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("Login failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (execute.getStatus() == 400) {
|
|
|
|
|
+ throw BusinessRuntimeException.getInstance("wrong MFA code.");
|
|
|
|
|
+ }else {
|
|
|
|
|
+ throw BusinessRuntimeException.getInstance("error login.");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String getAccessToken(String codeVerifier, String Location, String username) {
|
|
|
|
|
+ //com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback?code=jeix6iK_JWoUBuL7QUBeI_pryDHVwvnINqRFjttMfX4NK
|
|
|
|
|
+ if (!Location.contains("code")) {
|
|
|
|
|
+ log.info("Login code failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+ String code = Location.split("\\?code=")[1];
|
|
|
|
|
+ String url = "https://auth0.openai.com/oauth/token";
|
|
|
|
|
+ Map<String, String> headers = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ headers.put("User-Agent", user_agent);
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
|
|
+ map.put("redirect_uri", "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback");
|
|
|
|
|
+ map.put("grant_type", "authorization_code");
|
|
|
|
|
+ map.put("client_id", "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh");
|
|
|
|
|
+ map.put("code", code);
|
|
|
|
|
+ map.put("code_verifier", codeVerifier);
|
|
|
|
|
+
|
|
|
|
|
+ HttpResponse execute = HttpRequest.post(url).setProxy(proxy).headerMap(headers, true).cookie(getCookie()).form(map).execute();
|
|
|
|
|
+ /**
|
|
|
|
|
+ * {
|
|
|
|
|
+ * "access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL3Byb2ZpbGUiOnsiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWV9LCJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdWQiOlsiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MSIsImh0dHBzOi8vb3BlbmFpLm9wZW5haS5hdXRoMGFwcC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjg1Njc0ODA3LCJleHAiOjE2ODY4ODQ0MDcsImF6cCI6InBkbExJWDJZNzJNSWwycmhMaFRFOVZWOWJOOTA1a0JoIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCBtb2RlbC5yZWFkIG1vZGVsLnJlcXVlc3Qgb3JnYW5pemF0aW9uLnJlYWQgb2ZmbGluZV9hY2Nlc3MifQ.frAW5ZylGC1DcdpCvJo_9xo9mf-QrSRfSonNVxZocr25Y-92MEt7aqWu5IRS_J6Y0o82FzbcODQ2xFjJ5B_mGAJVuLRpfSfiEFJLzIfPF2d2s39hB-g9LqfdXmIQM3-rh7hAHuh6_nu9apdLt69lIakPd9w0XqgOfACQlHiZZND-MhnOp-l_LVoX3RmSJ2QWcxviLiAsdwMZhrNK7HH5mAlL8PDZCCOqA61NPi0pBpv3WIufLpesYOmJqyMg8QGKXppc7frgwJuXuZo_cKopZjHo9NAcbB_hfyp0QJUdPMiv_u_Si2fhJVOdb8zEVki-aZlHVZ-lYET4BaBeZSBHtg",
|
|
|
|
|
+ * "refresh_token":"LE_iTCK3WZfNV-RENjaA_JE8a5WkhMsEJjLKL8ZH_cpkD",
|
|
|
|
|
+ * "id_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaEVOVUpHTkVNMVFURTRNMEZCTWpkQ05UZzVNRFUxUlRVd1FVSkRNRU13UmtGRVFrRXpSZyJ9.eyJodHRwczovL2FwaS5vcGVuYWkuY29tL2F1dGgiOnsiZ3JvdXBzIjpbXSwib3JnYW5pemF0aW9ucyI6W3siaWQiOiJvcmctMGpFYUZaQVVTNkc1VHRCaHo1YjdSVlQ2IiwiaXNfZGVmYXVsdCI6dHJ1ZSwicm9sZSI6Im93bmVyIiwidGl0bGUiOiJQZXJzb25hbCJ9XSwidXNlcl9pZCI6InVzZXItdHNGczRvT3puTEdIWVhTeXRNZ2NtWldkIn0sIm5pY2tuYW1lIjoiYXVkcmV5Ym9vdGhjaGVsc2VhIiwibmFtZSI6ImF1ZHJleWJvb3RoY2hlbHNlYUBnbWFpbC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvOWNhM2U5NDY3OGZlODYzNWE0N2ZjOGE0NGU2ZTk3MWI_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZhdS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyMy0wNi0wMlQwMzowMDowMy4zMTZaIiwiZW1haWwiOiJhdWRyZXlib290aGNoZWxzZWFAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8iLCJhdWQiOiJwZGxMSVgyWTcyTUlsMnJoTGhURTlWVjliTjkwNWtCaCIsImlhdCI6MTY4NTY3NDgwNywiZXhwIjoxNjg1NzEwODA3LCJzdWIiOiJhdXRoMHw2NDcxZWZmNmIwYjUzOGVhOGZmNWEzNDAiLCJhdXRoX3RpbWUiOjE2ODU2NzQ4MDMsInNpZCI6ImxDbEk5cnVibVYzcE5aQjNqd1JPYm5iT2toeTl3RmFRIn0.zD464ErSUS7_q-BhGksLzK5kcy9mDEzrpZxSO4cqHci09KaWSPgCvm8S2N0fF3pDFw9juCpiN8RfqnPXJG2oCCJhUiTDHzX2yux6qf5IEdNe-wwdqoD7fLUv7JsdkZS-wXIHlvYOhFg3lRuE5mqvDOXR8lDCF_WEuqftYuWVD8DijwrA8a0GybFyj-idxYoJcWFYaHae6KTai8RHnGRERf8L4R0N1rnx86YzXsXl4-ZHnkTYR7X3J66k05gKsZY_TGoejae7kXs66UWeoMu4PjtLHKrsCW98X_1cjU3oXnqi40jwylZ5GCMn_V77WRAI-Q-0lbZNesGYJy8bF0Hz4Q",
|
|
|
|
|
+ * "scope":"openid profile email model.read model.request organization.read offline_access",
|
|
|
|
|
+ * "expires_in":1209600,
|
|
|
|
|
+ * "token_type":"Bearer"
|
|
|
|
|
+ * }
|
|
|
|
|
+ */
|
|
|
|
|
+ if (execute.getStatus() == 200) {
|
|
|
|
|
+ log.info(execute.body());
|
|
|
|
|
+ JSONObject accessToken = new JSONObject(execute.body());
|
|
|
|
|
+ redisService.set(RedisKey.CHATGPT_ACCESS_TOKEN + username, accessToken.getStr("access_token"),accessToken.getLong("expires_in"));
|
|
|
|
|
+ return accessToken.getStr("refresh_token");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|