/***************************************************************************
* Copyright 2001-2008 The VietSpider All rights reserved. *
**************************************************************************/
package org.vietspider.browser;
import java.math.BigInteger;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.vietspider.browser.VirtualFormPost.ParamValue;
import org.vietspider.chars.CharsDecoder;
import org.vietspider.chars.URLUtils;
import org.vietspider.common.io.LogService;
import org.vietspider.common.io.UtilFile;
import org.vietspider.html.HTMLNode;
import org.vietspider.html.Name;
import org.vietspider.html.parser.NodeImpl;
import org.vietspider.html.util.HTMLParserDetector;
import org.vietspider.net.client.HttpHandlers;
import org.vietspider.net.client.HttpMethodHandler;
import org.vietspider.net.client.HttpResponseReader;
import org.vietspider.net.client.WebClient;
import org.vietspider.token.attribute.Attributes;
/**
* Author : Nhu Dinh Thuan
* nhudinhthuan@yahoo.com
* Jul 23, 2008
*/
public class LoginWebsiteHandler {
private final static String TYPE_ATTR = "type";
private final static String PASSWORD = "password";
private final static String ID_ATTR = "id";
private final static String NAME_ATTR = "name";
private final static String VALUE = "value";
private final static String ACTION = "action";
private HashMap<String, ParamValue> maps;
public LoginWebsiteHandler() {
maps = new HashMap<String, ParamValue>();
}
public boolean login(HttpMethodHandler httpMethod, String referer,
String charset, URL loginUrl, String username, String password) throws Exception {
HttpResponse response = httpMethod.execute(loginUrl.toString(), referer);
if(response == null) return false;
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
switch (statusCode) {
case HttpStatus.SC_NOT_FOUND:
case HttpStatus.SC_NO_CONTENT:
case HttpStatus.SC_BAD_REQUEST:
case HttpStatus.SC_REQUEST_TIMEOUT:
case HttpStatus.SC_NOT_ACCEPTABLE:
case HttpStatus.SC_SERVICE_UNAVAILABLE:
case 999:
throw new Exception(statusLine.getReasonPhrase());
default:
break;
}
HttpResponseReader responseReader = HttpHandlers.getInstance().createReader();
byte [] data = responseReader.readBody(response);
HTMLParserDetector htmlParser2 = new HTMLParserDetector();
if(data == null) return false;
if(charset == null) {
charset = htmlParser2.detectCharset(data);
}
char [] chars = CharsDecoder.decode(charset, data, 0, data.length);
List<NodeImpl> tokens = htmlParser2.createTokens(chars);
if(tokens == null) return false;
int start = searchPasswordField(tokens);
LoginUtils loginUtil = new LoginUtils();
if(start == -1) {
throw new UnknownHostException("Not found login form. Please check login address: "+loginUrl);
}
for(; start > -1; start--) {
NodeImpl node = tokens.get(start);
if(node.isNode(Name.FORM)) break;
}
HTMLNode form = null;
boolean md5 = false;
List<HTMLNode> inputs = new ArrayList<HTMLNode>();
String formValue = null;
for(int i = start; i < tokens.size(); i++) {
NodeImpl node = tokens.get(i);
if(node.isNode(Name.FORM)) {
if(node.isOpen()) {
if(!md5) {
String value = new String(node.getValue());
md5 = value.toLowerCase().indexOf("md5") > -1;
}
form = node;
formValue = new String(form.getValue()).toLowerCase();
} else {
break;
}
} else if(node.isNode(Name.INPUT)) {
if(!md5 && formValue != null) {
md5 = formValue.indexOf("md5") > -1;
}
inputs.add(node);
}
}
if(form == null || inputs.size() < 1) return false;
String address = getAttribute(form, ACTION);
if(address == null) return false;
List<NameValuePair> params = new ArrayList<NameValuePair>();
for(int i = 0 ; i < inputs.size(); i++) {
Attributes attrs = inputs.get(i).getAttributes();
String name = getAttribute(attrs, NAME_ATTR);
if(name == null) getAttribute(attrs, ID_ATTR);
if(name == null) continue;
String type = getAttribute(attrs, TYPE_ATTR);
if(type == null) type = "text";
if(type.equalsIgnoreCase("text")) {
// System.out.println(name + " : "+ username);
params.add(new BasicNameValuePair(name, username));
} else if(type.equalsIgnoreCase(PASSWORD)) {
if(md5) password = hexMd5(password);
// System.out.println(name + " : "+ password);
// params.add(new BasicNameValuePair(name, password));
//@TODO Hashcode
// System.out.println(formValue+ " : " + formValue.indexOf("vb_login_md5password"));
if(formValue.indexOf("vb_login_md5password") > -1) {
params.add(new BasicNameValuePair(name, ""));
params.add(new BasicNameValuePair("vb_login_md5password", password));
params.add(new BasicNameValuePair("vb_login_md5password_utf", password));
} else {
params.add(new BasicNameValuePair(name, password));
}
} else {
String value = "";
ParamValue paramValues = maps.get(name);
if(paramValues == null) {
value = getAttribute(attrs, VALUE);
} else {
value = paramValues.getValues()[0];
}
if(value != null) {
// System.out.println(name + " : "+ value);
params.add(new BasicNameValuePair(name, value == null ? "" : value.trim()));
}
}
}
URLUtils urlUtils = new URLUtils();
address = urlUtils.createURL(loginUrl, address).trim();
address = urlUtils.getCanonical(address);
referer = loginUrl.toString();
WebClient webClient = httpMethod.getWebClient();
HttpHost httpHost = webClient.createHttpHost(address);
HttpPost httpPost = webClient.createFormPostMethod(address, referer, params);
HttpResponse response2 = httpMethod.execute(httpHost, httpPost);
/*statusLine = response2.getStatusLine();
statusCode = statusLine.getStatusCode();
if(statusCode == HttpStatus.SC_MOVED_PERMANENTLY
|| statusCode == HttpStatus.SC_SEE_OTHER
|| statusCode == HttpStatus.SC_TEMPORARY_REDIRECT) {
Header header = response2.getFirstHeader("Location");
if(header != null
&& header.getValue() != null
&& !header.getValue().trim().isEmpty()) {
System.out.println(header.getValue());
try {
response2 = httpMethod.execute(header.getValue(), null);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println(" da xong roi ");
}
}*/
// System.out.println("status code "+ statusCode);
// Header [] headers = response2.getAllHeaders();
// for(Header header : headers) {
// System.out.println(header.getName() + " : " + header.getValue());
// }
byte [] bytes = new byte[0];
// org.vietspider.common.io.DataWriter writer = new org.vietspider.common.io.DataWriter();
// java.io.File file = UtilFile.getFile("track/logs/", "login_" + Utils.toFileName(address));
loginUtil.setPrevLogin(tokens);
boolean error = false;
try {
bytes = responseReader.readBody(response2);
} catch (SocketException e) {
LogService.getInstance().setMessage("WEB", e, e.toString());
bytes = e.toString().getBytes();
error = true;
} catch (Exception e) {
LogService.getInstance().setThrowable("WEB", e);
bytes = e.toString().getBytes();
error = true;
}
if(webClient.isLog()) {
java.io.File file = UtilFile.getFile("track/logs/", "login_" + Utils.toFileName(address));
LogService.getInstance().setMessage("WEB", null, "Login to: " +address);
new org.vietspider.common.io.DataWriter().save(file, bytes);
}
if(bytes == null || bytes.length < 1) {
error = true;
throw new Exception("No response from server.");
}
if(!error) {
chars = CharsDecoder.decode(charset, bytes, 0, bytes.length);
tokens = htmlParser2.createTokens(chars);
if(tokens == null) return false;
loginUtil.setAfterLogin(tokens);
if(searchPasswordField(tokens) > 0) throw new Exception(loginUtil.getError());
}
return !error;
}
private String getAttribute(HTMLNode node, String name) {
Attributes attrs = node.getAttributes();
int idx = attrs.indexOf(name);
if(idx < 0) return null;
return attrs.get(idx).getValue();
}
private String getAttribute(Attributes attrs, String name) {
int idx = attrs.indexOf(name);
if(idx < 0) return null;
return attrs.get(idx).getValue();
}
private String hexMd5(String password) throws Exception {
// System.out.println("===== > "+ password);
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password.getBytes());
BigInteger hash = new BigInteger(1, md5.digest());
return pad(hash.toString(16), 32, '0');
}
private static String pad(String s, int length, char pad) {
StringBuffer buffer = new StringBuffer(s);
while (buffer.length() < length) {
buffer.insert(0, pad);
}
return buffer.toString();
}
private int searchPasswordField(List<NodeImpl> tokens) {
for(int i = 0; i < tokens.size(); i++) {
NodeImpl node = tokens.get(i);
if(!node.isNode(Name.INPUT)) continue;
String value = getAttribute(node, TYPE_ATTR);
if(value == null) continue;
if(value.equalsIgnoreCase(PASSWORD)) return i;
}
return -1;
}
public void resetData() { maps.clear(); }
public void putData(String key, String...values) { maps.put(key, new ParamValue(values)); }
public void putData(String line) {
String [] elements = line.split("\\=");
// System.out.println(" thay co "+ line + " : " + elements.length);
maps.put(elements[0], new ParamValue(elements[1]));
}
}