/******************************************************************************
* *
* Copyright 2016 Subterranean Security *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*****************************************************************************/
package com.subterranean_security.crimson.viewer.ui.screen.login;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.text.BadLocationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.subterranean_security.crimson.core.net.Connector;
import com.subterranean_security.crimson.core.net.Connector.ConnectionType;
import com.subterranean_security.crimson.core.net.MessageFuture.Timeout;
import com.subterranean_security.crimson.core.proto.Misc.Outcome;
import com.subterranean_security.crimson.core.store.ConnectionStore;
import com.subterranean_security.crimson.core.ui.FieldLimiter;
import com.subterranean_security.crimson.core.ui.StatusLabel;
import com.subterranean_security.crimson.core.util.ValidationUtil;
import com.subterranean_security.crimson.cv.net.command.CvidCom;
import com.subterranean_security.crimson.universal.Universal;
import com.subterranean_security.crimson.universal.stores.DatabaseStore;
import com.subterranean_security.crimson.viewer.ViewerState;
import com.subterranean_security.crimson.viewer.net.ViewerExecutor;
import com.subterranean_security.crimson.viewer.net.command.LoginCom;
import com.subterranean_security.crimson.viewer.store.ProfileStore;
import com.subterranean_security.crimson.viewer.ui.UICommon;
import com.subterranean_security.crimson.viewer.ui.UIUtil;
public class LoginPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(LoginPanel.class);
private JTextField fld_user;
public JButton btn_cancel;
public JButton btn_login;
private JPasswordField fld_pass;
private JComboBox<String> fld_address;
private JTextField fld_port;
private JPanel panel_server;
private JLabel lbl_address;
private JLabel lbl_port;
private JPanel panel_credentials;
private LoginDialog parent;
private StatusLabel lbl_status;
private JLabel lbl_user;
private JLabel lbl_pass;
private Border fld_port_border;
private Border fld_password_border;
private Border fld_user_border;
private Border fld_server_border;
public boolean result = false;
public LoginPanel(final LoginDialog parent) {
this.parent = parent;
init();
if (Universal.debug) {
fld_user.setText("admin");
fld_pass.setText("default");
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(500);
return null;
}
protected void done() {
for (char c : "10101".toCharArray()) {
fld_port.dispatchEvent(new KeyEvent(fld_port, KeyEvent.KEY_TYPED, System.currentTimeMillis(),
KeyEvent.KEY_FIRST, KeyEvent.VK_UNDEFINED, c));
}
};
}.execute();
}
}
private void init() {
setPreferredSize(new Dimension(400, 248));
setBorder(null);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel panel_header = new JPanel();
panel_header.setBackground(UICommon.bg);
panel_header.setBorder(new EtchedBorder(EtchedBorder.RAISED, null, null));
add(panel_header);
panel_header.setLayout(null);
JLabel logo = new JLabel("");
logo.setIcon(new ImageIcon(LoginPanel.class
.getResource("/com/subterranean_security/crimson/viewer/ui/res/image/crimson_logo-login.png")));
logo.setBounds(94, 0, 210, 105);
panel_header.add(logo);
JPanel panel_body = new JPanel();
panel_body.setPreferredSize(new Dimension(10, 30));
panel_body.setBorder(new EtchedBorder(EtchedBorder.RAISED, null, null));
add(panel_body);
panel_body.setLayout(null);
panel_server = new JPanel();
panel_server.setBounds(6, 6, 388, 54);
panel_body.add(panel_server);
panel_server.setBorder(new TitledBorder(new LineBorder(new Color(184, 207, 229)), "Server", TitledBorder.CENTER,
TitledBorder.TOP, null, null));
panel_server.setLayout(null);
lbl_address = new JLabel("Address");
lbl_address.setBounds(20, 12, 280, 15);
lbl_address.setFont(new Font("Dialog", Font.BOLD, 10));
panel_server.add(lbl_address);
fld_address = new JComboBox<String>();
fld_address.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (fld_address.getSelectedIndex() == -1) {
return;
}
String[] parts = ((String) fld_address.getSelectedItem()).split(":");
String server = null;
String port = null;
switch (parts[0]) {
case "Local Server": {
server = "127.0.0.1";
port = "10101";
break;
}
case "Live Example Server": {
server = "example.subterranean-security.com";
port = "10101";
fld_user.setText("testuser");
fld_pass.setText("this-password-does-not-matter");
break;
}
default: {
if (parts.length == 2) {
server = parts[0];
port = parts[1];
} else {
return;
}
}
}
// insert info
fld_address.setSelectedItem(server);
// insert port
try {
fld_port.getDocument().remove(0, fld_port.getDocument().getLength());
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO find better way to add text to field
for (char c : port.toCharArray()) {
fld_port.dispatchEvent(new KeyEvent(fld_port, KeyEvent.KEY_TYPED, System.currentTimeMillis(),
KeyEvent.KEY_FIRST, KeyEvent.VK_UNDEFINED, c));
}
}
});
fld_address.setFont(new Font("Dialog", Font.PLAIN, 10));
fld_server_border = fld_address.getBorder();
fld_address.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
lbl_status.setInfo("enter an ip address, hostname, or DNS name");
}
@Override
public void mouseExited(MouseEvent e) {
lbl_status.setDefault();
}
});
fld_address.setBounds(20, 28, 280, 17);
fld_address.setMaximumSize(new Dimension(59, 19));
panel_server.add(fld_address);
fld_address.setEditable(true);
lbl_port = new JLabel("Port");
lbl_port.setHorizontalAlignment(SwingConstants.CENTER);
lbl_port.setBounds(312, 12, 56, 15);
lbl_port.setFont(new Font("Dialog", Font.BOLD, 10));
panel_server.add(lbl_port);
fld_port = new JTextField();
fld_port.setFont(new Font("Dialog", Font.PLAIN, 10));
fld_port_border = fld_port.getBorder();
fld_port.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
lbl_status.setInfo("corresponding port on the server");
}
@Override
public void mouseExited(MouseEvent e) {
lbl_status.setDefault();
}
});
fld_port.setDocument(new FieldLimiter(5, "\\d"));
fld_port.setBounds(312, 28, 56, 17);
fld_port.setPreferredSize(new Dimension(25, 19));
fld_port.setMinimumSize(new Dimension(25, 19));
fld_port.setHorizontalAlignment(SwingConstants.CENTER);
fld_port.setMaximumSize(new Dimension(25, 19));
panel_server.add(fld_port);
fld_port.setColumns(10);
panel_credentials = new JPanel();
panel_credentials.setBounds(6, 60, 388, 55);
panel_body.add(panel_credentials);
panel_credentials.setBorder(new TitledBorder(new LineBorder(new Color(184, 207, 229)), "Credentials",
TitledBorder.CENTER, TitledBorder.TOP, null, null));
panel_credentials.setLayout(null);
fld_user = new JTextField();
fld_user.setFont(new Font("Dialog", Font.PLAIN, 10));
fld_user_border = fld_user.getBorder();
fld_user.setDocument(new FieldLimiter(60));
fld_user.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
lbl_status.setInfo("username to an account on the server");
}
@Override
public void mouseExited(MouseEvent e) {
lbl_status.setDefault();
}
});
fld_user.setHorizontalAlignment(SwingConstants.CENTER);
fld_user.setBounds(20, 28, 140, 19);
fld_user.setMaximumSize(new Dimension(100, 19));
panel_credentials.add(fld_user);
fld_user.setColumns(10);
fld_pass = new JPasswordField();
fld_pass.setFont(new Font("Dialog", Font.PLAIN, 8));
fld_password_border = fld_pass.getBorder();
fld_pass.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
lbl_status.setInfo("corresponding case-sensitive password");
}
@Override
public void mouseExited(MouseEvent e) {
lbl_status.setDefault();
}
});
fld_pass.setDocument(new FieldLimiter(64));
fld_pass.setHorizontalAlignment(SwingConstants.CENTER);
fld_pass.setBounds(228, 28, 140, 19);
fld_pass.setMaximumSize(new Dimension(100, 19));
panel_credentials.add(fld_pass);
lbl_user = new JLabel("Username");
lbl_user.setHorizontalAlignment(SwingConstants.CENTER);
lbl_user.setFont(new Font("Dialog", Font.BOLD, 10));
lbl_user.setBounds(20, 12, 140, 15);
panel_credentials.add(lbl_user);
lbl_pass = new JLabel("Password");
lbl_pass.setHorizontalAlignment(SwingConstants.CENTER);
lbl_pass.setFont(new Font("Dialog", Font.BOLD, 10));
lbl_pass.setBounds(228, 12, 140, 15);
panel_credentials.add(lbl_pass);
lbl_status = new StatusLabel("Enter details to login to a crimson server");
lbl_status.setVisible(true);
lbl_status.setBounds(12, 120, 376, 15);
panel_body.add(lbl_status);
btn_cancel = new JButton("Exit");
btn_cancel.setMargin(new Insets(0, 5, 0, 5));
btn_cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.exit(0);
}
});
btn_cancel.setPreferredSize(new Dimension(60, 25));
btn_cancel.setMaximumSize(new Dimension(60, 25));
btn_login = new JButton("Login");
btn_login.setMargin(new Insets(0, 5, 0, 5));
btn_login.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
login((String) fld_address.getSelectedItem(), fld_port.getText(), fld_user.getText());
}
});
btn_login.setPreferredSize(new Dimension(60, 25));
btn_login.setMaximumSize(new Dimension(60, 25));
}
private void login(String server, String port, String user) {
if (!testValues(server, port, user)) {
return;
}
startLogin();
new SwingWorker<Outcome, Void>() {
@Override
protected Outcome doInBackground() throws Exception {
long t1 = System.currentTimeMillis();
Outcome.Builder outcome = Outcome.newBuilder().setResult(false);
Connector connector = new Connector(new ViewerExecutor());
try {
connector.connect(ConnectionType.SOCKET, server, Integer.parseInt(port));
ConnectionStore.add(connector);
} catch (Exception e) {
try {
outcome.setComment(
"Unable to connect to server: " + InetAddress.getByName(server).getHostAddress());
} catch (UnknownHostException e1) {
outcome.setComment("Unable to resolve server: " + server);
}
return outcome.build();
}
try {
CvidCom.getCvid(connector);
} catch (Timeout e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// set local viewer profile name
ProfileStore.setLocalUser(user);
// request login from server
Outcome loginOutcome = LoginCom.login(user, UIUtil.getPassword(fld_pass));
result = loginOutcome.getResult();
if (result) {
outcome.setResult(true);
ViewerState.goOnline(server, Integer.parseInt(port));
// TODO relocate
if (!server.equals("127.0.0.1")) {
// update recents
try {
String successfulLogin = server + ":" + port;
ArrayList<String> recents = (ArrayList<String>) DatabaseStore.getDatabase()
.getObject("login.recents");
recents.remove(successfulLogin);
recents.add(successfulLogin);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
ConnectionStore.closeAll();
if (loginOutcome.hasComment())
outcome.setComment(loginOutcome.getComment());
}
return outcome.setTime(System.currentTimeMillis() - t1).build();
}
protected void done() {
try {
Outcome outcome = get();
lbl_status.unfreeze();
if (outcome.getResult()) {
lbl_status.setGood("Login completed in: " + outcome.getTime() + "ms");
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(650);
return null;
}
protected void done() {
synchronized (parent) {
parent.notifyAll();
}
parent.dispose();
}
}.execute();
} else {
lbl_status.setBad(outcome.getComment());
}
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
endLogin();
}
};
}.execute();
}
private boolean testValues(String server, String port, String user) {
removeErrorBorders();
if (!ValidationUtil.port(port)) {
setPortError();
return false;
}
if (!ValidationUtil.password(fld_pass)) {
setPassError();
return false;
}
if (!ValidationUtil.username(user)) {
setUserError();
return false;
}
if (!ValidationUtil.dns(server) && !ValidationUtil.ipv4(server)) {
setServerError();
return false;
}
return true;
}
private void startLogin() {
btn_login.setEnabled(false);
fld_pass.setEnabled(false);
fld_port.setEnabled(false);
fld_address.setEnabled(false);
fld_user.setEnabled(false);
lbl_address.setEnabled(false);
lbl_port.setEnabled(false);
lbl_pass.setEnabled(false);
lbl_user.setEnabled(false);
lbl_status.setInfo("Attempting Connection");
lbl_status.freeze();
}
private void endLogin() {
btn_login.setEnabled(true);
fld_pass.setEnabled(true);
fld_port.setEnabled(true);
fld_address.setEnabled(true);
fld_user.setEnabled(true);
lbl_address.setEnabled(true);
lbl_port.setEnabled(true);
lbl_pass.setEnabled(true);
lbl_user.setEnabled(true);
lbl_status.unfreeze();
}
private void removeErrorBorders() {
fld_address.setBorder(fld_server_border);
fld_port.setBorder(fld_port_border);
fld_user.setBorder(fld_user_border);
fld_pass.setBorder(fld_password_border);
}
private void setServerError() {
fld_address.setBorder(new LineBorder(Color.RED));
lbl_status.setBad("Invalid server address");
}
private void setPortError() {
fld_port.setBorder(new LineBorder(Color.RED));
lbl_status.setBad("Invalid server port");
}
private void setUserError() {
fld_user.setBorder(new LineBorder(Color.RED));
lbl_status.setBad("Invalid username");
}
private void setPassError() {
fld_pass.setBorder(new LineBorder(Color.RED));
lbl_status.setBad("Invalid password");
}
public void addRecents(boolean localServer) {
ArrayList<String> r = new ArrayList<String>();
try {
r.addAll((ArrayList<String>) DatabaseStore.getDatabase().getObject("login.recents"));
} catch (Exception e) {
log.error("Failed to load recent connections");
e.printStackTrace();
return;
}
r.add(0, "Live Example Server");
if (localServer) {
r.add(0, "Local Server");
}
String[] recent = new String[r.size()];
for (int i = 0; i < r.size(); i++) {
recent[i] = r.get(i);
}
fld_address.setModel(new DefaultComboBoxModel<String>(recent));
fld_address.setSelectedIndex(-1);
}
}