Skip to content

Fix compatibility #245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/LoginHelp.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
</p>

## browser login
This login requires additional download of dependent files. Download the compressed package with the version number ** jcef ** at the [releases](https://github.com/shuzijun/leetcode-editor/releases) address. After downloading, decompress it to the path of JCEFFilePath shown on the configuration page.
If there is a resource file in the path, this login method will be used first, but this method is not compatible. If it cannot be loaded normally, you need to delete the contents of the folder and log in using other methods.
~~This login requires additional download of dependent files. Download the compressed package with the version number ** jcef ** at the [releases](https://github.com/shuzijun/leetcode-editor/releases) address. After downloading, decompress it to the path of JCEFFilePath shown on the configuration page.~~
~~If there is a resource file in the path, this login method will be used first, but this method is not compatible. If it cannot be loaded normally, you need to delete the contents of the folder and log in using other methods.~~
Starting from version 6.8, external mounting of JCEF is no longer supported. Instead, JCEF provided by JetBrains is used. The supported version is 2020.2+. If you meet the conditions of use, you can check JCEF in the configuration item.
7 changes: 4 additions & 3 deletions doc/LoginHelp_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</p>

## 浏览器登录
此登录需要额外下载依赖文件,在地址[releases](https://github.com/shuzijun/leetcode-editor/releases)下载版号带有**jcef**的压缩包,
下载后,解压到配置页展示的JCEFFilePath的路径中。
如路径中存在资源文件,将首先使用此登录方式,但此方式兼容性差,如不能正常加载,需删除文件夹下内容,使用其他方式登录。
~~此登录需要额外下载依赖文件,在地址[releases](https://github.com/shuzijun/leetcode-editor/releases)下载版号带有**jcef**的压缩包,~~
~~下载后,解压到配置页展示的JCEFFilePath的路径中。 ~~
~~如路径中存在资源文件,将首先使用此登录方式,但此方式兼容性差,如不能正常加载,需删除文件夹下内容,使用其他方式登录。~~
从版本6.8开始,不再支持外部挂载JCEF,改用JetBrains提供的JCEF,支持版本为2020.2+,如果满足使用条件,可以在配置项中勾选JCEF
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import com.shuzijun.leetcode.plugin.model.Config;
import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
import com.shuzijun.leetcode.plugin.utils.*;
import com.shuzijun.leetcode.plugin.window.LoginFrame;
import com.shuzijun.leetcode.plugin.window.WindowFactory;
import com.shuzijun.leetcode.plugin.window.*;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
Expand All @@ -20,8 +19,8 @@
*/
public class LoginAction extends AbstractAction {

@Override
public void actionPerformed(AnActionEvent anActionEvent, Config config) {
@Override
public void actionPerformed(AnActionEvent anActionEvent, Config config) {

JTree tree = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE);

Expand Down Expand Up @@ -61,22 +60,16 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) {
}
}


if (URLUtils.leetcodecn.equals(URLUtils.getLeetcodeHost())) {
if (!LoginFrame.httpLogin.ajaxLogin(config, tree, anActionEvent.getProject())) {
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
LoginFrame loginFrame = new LoginFrame(anActionEvent.getProject(), tree);
loginFrame.loadComponent();
}
});
}
} else {
if (!HttpLogin.ajaxLogin(config, tree, anActionEvent.getProject())) {
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
LoginFrame loginFrame = new LoginFrame(anActionEvent.getProject(), tree);
LoginFrame loginFrame;
if (HttpLogin.isSupportedJcef()) {
loginFrame = new JcefLogin(anActionEvent.getProject(), tree);
} else {
loginFrame = new CookieLogin(anActionEvent.getProject(), tree);
}
loginFrame.loadComponent();
}
});
Expand Down
13 changes: 3 additions & 10 deletions src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.intellij.ui.components.JBPasswordField;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.jcef.JBCefApp;
import com.intellij.util.net.HttpConfigurable;
import com.shuzijun.leetcode.plugin.listener.ColorListener;
import com.shuzijun.leetcode.plugin.listener.DonateListener;
Expand All @@ -25,6 +24,7 @@
import com.shuzijun.leetcode.plugin.utils.MTAUtils;
import com.shuzijun.leetcode.plugin.utils.PropertiesUtils;
import com.shuzijun.leetcode.plugin.utils.URLUtils;
import com.shuzijun.leetcode.plugin.window.HttpLogin;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
Expand Down Expand Up @@ -92,15 +92,8 @@ public void mouseClicked(MouseEvent e) {
}
}
});
Boolean jcefSupported;
try {
jcefSupported = JBCefApp.isSupported();
}catch (Throwable e){
jcefSupported = false;
}
if(!jcefSupported){
proxyCheckBox.setEnabled(true);
}

jcefCheckBox.setEnabled(!HttpLogin.isSupportedJcef());

templateConfigHelp.addMouseListener(new MouseAdapter() {
@Override
Expand Down
131 changes: 131 additions & 0 deletions src/main/java/com/shuzijun/leetcode/plugin/window/CookieLogin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package com.shuzijun.leetcode.plugin.window;

import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBPanel;
import com.intellij.ui.components.JBScrollPane;
import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils;
import com.shuzijun.leetcode.plugin.utils.PropertiesUtils;
import com.shuzijun.leetcode.plugin.utils.URLUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.List;

/**
* @author shuzijun
*/
public class CookieLogin implements LoginFrame {
private JTree tree;
private Project project;


public CookieLogin(Project project, JTree tree) {
this.tree = tree;
this.project = project;
}

@Override
public void loadComponent() {
CookiePanel cookiePanel = new CookiePanel(project);
if (cookiePanel.showAndGet()) {
String cookiesString = cookiePanel.cookieText();
if (StringUtils.isBlank(cookiesString)) {
JOptionPane.showMessageDialog(null, "cookie is null");
return;
}
final List<HttpCookie> cookieList = new ArrayList<>();
String[] cookies = cookiesString.split(";");
for (String cookieString : cookies) {
String[] cookie = cookieString.trim().split("=");
if (cookie.length >= 2) {
try {
HttpCookie basicClientCookie = new HttpCookie(cookie[0], cookie[1]);
basicClientCookie.setDomain("." + URLUtils.getLeetcodeHost());
basicClientCookie.setPath("/");
cookieList.add(basicClientCookie);
} catch (IllegalArgumentException ignore) {

}
}
}
HttpRequestUtils.setCookie(cookieList);

ProgressManager.getInstance().run(new Task.Backgroundable(project, "leetcode.loginSuccess", false) {
@Override
public void run(@NotNull ProgressIndicator progressIndicator) {
if (HttpRequestUtils.isLogin()) {
HttpLogin.loginSuccess(tree, project, cookieList);
} else {
JOptionPane.showMessageDialog(null, PropertiesUtils.getInfo("login.failed"));
}

}
});
}
}

class CookiePanel extends DialogWrapper {

private JPanel jpanel;
private JTextArea caseText;

public CookiePanel(Project project) {
super(project, Boolean.TRUE);

jpanel = new JBPanel();
jpanel.setLayout(new BorderLayout());
caseText = new JTextArea();
caseText.setLineWrap(true);
caseText.setMinimumSize(new Dimension(400, 200));
caseText.setPreferredSize(new Dimension(400, 200));
jpanel.add(new JBScrollPane(caseText, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
setModal(true);
init();
setTitle("Cookie login");
}

@NotNull
@Override
protected Action getOKAction() {
Action action = super.getOKAction();
action.putValue(Action.NAME, "login");
return action;
}

@NotNull
@Override
protected Action[] createActions() {
Action helpAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
BrowserUtil.browse("https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp.md");
}

};
helpAction.putValue(Action.NAME, "help");
Action[] actions = new Action[]{helpAction, this.getOKAction(), this.getCancelAction()};
return actions;
}

@Nullable
@Override
protected JComponent createCenterPanel() {
return jpanel;
}

public String cookieText() {
return caseText.getText();
}
}
}
158 changes: 158 additions & 0 deletions src/main/java/com/shuzijun/leetcode/plugin/window/HttpLogin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package com.shuzijun.leetcode.plugin.window;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.shuzijun.leetcode.plugin.manager.ViewManager;
import com.shuzijun.leetcode.plugin.model.Config;
import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
import com.shuzijun.leetcode.plugin.utils.*;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.lang.reflect.Method;
import java.net.HttpCookie;
import java.util.List;

/**
* @author shuzijun
*/
public class HttpLogin {
public static boolean ajaxLogin(Config config, JTree tree, Project project) {

if (URLUtils.leetcode.equals(URLUtils.getLeetcodeHost())) {
return Boolean.FALSE;
}

if (StringUtils.isBlank(PersistentConfig.getInstance().getPassword())) {
return Boolean.FALSE;
}

try {
HttpEntity ent = MultipartEntityBuilder.create()
.addTextBody("csrfmiddlewaretoken", HttpRequestUtils.getToken())
.addTextBody("login", config.getLoginName())
.addTextBody("password", PersistentConfig.getInstance().getPassword())
.addTextBody("next", "/problems")
.build();
HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeLogin(), ent.getContentType().getValue());
httpRequest.setBody(IOUtils.toString(ent.getContent(), "UTF-8"));
httpRequest.addHeader("x-requested-with", "XMLHttpRequest");
httpRequest.addHeader("accept", "*/*");
HttpResponse response = HttpRequestUtils.executePost(httpRequest);

if (response == null) {
MessageUtils.getInstance(project).showWarnMsg("warning", PropertiesUtils.getInfo("request.failed"));
return Boolean.FALSE;
}

String body = response.getBody();

if ((response.getStatusCode() == 200 || response.getStatusCode() == 302)) {
if (StringUtils.isNotBlank(body) && body.startsWith("{")) {
JSONObject jsonObject = JSONObject.parseObject(body);
JSONArray jsonArray = jsonObject.getJSONObject("form").getJSONArray("errors");
if (jsonArray.isEmpty()) {
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
examineEmail(project);
ViewManager.loadServiceData(tree, project);
return Boolean.TRUE;
} else {
MessageUtils.getInstance(project).showInfoMsg("info", StringUtils.join(jsonArray, ","));
return Boolean.FALSE;
}
} else if (StringUtils.isBlank(body)) {
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
examineEmail(project);
ViewManager.loadServiceData(tree, project);
return Boolean.TRUE;
} else {
HttpRequestUtils.resetHttpclient();
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.unknown"));
SentryUtils.submitErrorReport(null, String.format("login.unknown:\nStatusCode:%s\nbody:%s", response.getStatusCode(), body));
return Boolean.FALSE;
}
} else if (response.getStatusCode() == 400) {
JSONObject jsonObject = JSONObject.parseObject(body);
MessageUtils.getInstance(project).showInfoMsg("info", StringUtils.join(jsonObject.getJSONObject("form").getJSONArray("errors"), ","));
return Boolean.FALSE;
} else {
HttpRequestUtils.resetHttpclient();
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.unknown"));
SentryUtils.submitErrorReport(null, String.format("login.unknown:\nStatusCode:%s\nbody:%s", response.getStatusCode(), body));
return Boolean.FALSE;
}
} catch (Exception e) {
LogUtils.LOG.error("登陆错误", e);
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.failed"));
return Boolean.FALSE;
}
}

public static void examineEmail(Project project) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json");
try {
httpRequest.setBody("{\"operationName\":\"user\",\"variables\":{},\"query\":\"query user {\\n user {\\n socialAccounts\\n username\\n emails {\\n email\\n primary\\n verified\\n __typename\\n }\\n phone\\n profile {\\n rewardStats\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}");
httpRequest.addHeader("Accept", "application/json");
HttpResponse response = HttpRequestUtils.executePost(httpRequest);
if (response != null && response.getStatusCode() == 200) {

String body = response.getBody();

JSONArray jsonArray = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("user").getJSONArray("emails");
if (jsonArray != null && jsonArray.size() > 0) {
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
if (object.getBoolean("verified")) {
return;
}
}

}
MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("user.email"));
}
} catch (Exception i) {
LogUtils.LOG.error("验证邮箱错误");
}
}
});
}

public static void loginSuccess(JTree tree, Project project, List<HttpCookie> cookieList) {
ProgressManager.getInstance().run(new Task.Backgroundable(project, "leetcode.loginSuccess", false) {
@Override
public void run(@NotNull ProgressIndicator progressIndicator) {
Config config = PersistentConfig.getInstance().getInitConfig();
config.addCookie(config.getUrl() + config.getLoginName(), CookieUtils.httpCookieToJSONString(cookieList));
PersistentConfig.getInstance().setInitConfig(config);
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
ViewManager.loadServiceData(tree, project);
examineEmail(project);
}
});
}

public static boolean isSupportedJcef() {
try {
Class<?> JBCefAppClass = Class.forName("com.intellij.ui.jcef.JBCefApp");
Method method = JBCefAppClass.getMethod("isSupported");
boolean supported = (boolean) method.invoke(null);

Config config = PersistentConfig.getInstance().getInitConfig();
return config.getJcef() && supported;
} catch (Throwable e) {
return Boolean.FALSE;
}
}

}
Loading