package controllers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import net.nationstatesplusplus.assembly.util.DatabaseAccess;
import net.nationstatesplusplus.assembly.util.Utils;
import net.sourceforge.jwbf.core.RequestBuilder;
import net.sourceforge.jwbf.core.actions.util.HttpAction;
import net.sourceforge.jwbf.mediawiki.ApiRequestBuilder;
import net.sourceforge.jwbf.mediawiki.actions.util.MWAction;
import net.sourceforge.jwbf.mediawiki.bots.MediaWikiBot;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.dbutils.DbUtils;
import org.spout.cereal.config.ConfigurationNode;
import org.spout.cereal.config.yaml.YamlConfiguration;
import play.Logger;
import play.mvc.Result;
import play.mvc.Results;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.limewoodMedia.nsapi.NationStates;
public class NSWikiController extends NationStatesController {
private final String nswikiAdmin;
private final String nswikiPass;
public NSWikiController(DatabaseAccess access, YamlConfiguration config, NationStates api) {
super(access, config, api);
ConfigurationNode nswiki = getConfig().getChild("nswiki");
nswikiAdmin = nswiki.getChild("admin").getString(null);
nswikiPass = nswiki.getChild("password").getString(null);
}
public Result verifyNationLogin() throws IOException, SQLException {
Utils.handleDefaultPostHeaders(request(), response());
Result ret = Utils.validateRequest(request(), response(), getAPI(), getDatabase(), false);
if (ret != null) {
return ret;
}
String nation = Utils.getPostValue(request(), "nation");
String password = Utils.getPostValue(request(), "password");
if (password == null || password.isEmpty() || password.length() < 8) {
Logger.warn("NSWiki User [" + nation + "] attempted an invalid password: [" + password + "]");
return Results.badRequest("Invalid password");
}
Logger.info("Attempting NSWiki login for " + nation);
final String title;
Connection conn = null;
PreparedStatement select = null;
ResultSet set = null;
try {
conn = getConnection();
select = conn.prepareStatement("SELECT title FROM assembly.nation WHERE name = ?");
select.setString(1, Utils.sanitizeName(nation));
set = select.executeQuery();
set.next();
title = set.getString(1);
if (doesNSWikiUserExist(title)) {
Logger.info("NSWiki Updating password for " + title);
if (changePassword(conn, title, password)) {
return Results.ok();
}
return Results.internalServerError("Unable to change password for " + title);
}
} finally {
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(select);
DbUtils.closeQuietly(set);
}
return createNSWikiUser(title, password);
}
private static boolean changePassword(Connection conn, String user, String password) throws SQLException {
final String salt = new BigInteger(31, new Random()).toString(16);
final String hash = ":B:" + salt + ":" + DigestUtils.md5Hex(salt + "-" + DigestUtils.md5Hex(password));
PreparedStatement update = conn.prepareStatement("UPDATE nswiki.user SET user_password = ? WHERE user_name = ?");
update.setString(1, hash);
update.setString(2, user);
return update.executeUpdate() == 1;
}
private static boolean doesNSWikiUserExist(String user) throws IOException {
URL userPage = new URL("http://nswiki.org/index.php?title=User:" + URLEncoder.encode(user, "UTF-8"));
HttpURLConnection conn = (HttpURLConnection) userPage.openConnection();
conn.connect();
return conn.getResponseCode() / 100 == 2;
}
private Result createNSWikiUser(String nation, String password) throws IOException {
MediaWikiBot wikibot = new MediaWikiBot("http://nswiki.org/");
wikibot.login(nswikiAdmin, nswikiPass);
String result = wikibot.performAction(new CreateUser(nation, password));
if (result.toLowerCase().contains("success")) {
return Results.ok();
} else {
Logger.warn("Unable to create NSWiki user: " + result);
return Results.internalServerError();
}
}
private static class CreateUser extends MWAction {
private String token = null;
private int count = 0;
private final String name;
private final String password;
public CreateUser(String name, String password) {
this.name = name;
this.password = password;
}
@Override
public HttpAction getNextMessage() {
try {
RequestBuilder rb = new ApiRequestBuilder().action("createaccount").param("format", "json").param("name", URLEncoder.encode(name, "UTF-8")).param("password", URLEncoder.encode(password, "UTF-8"));
if (token != null) {
rb.param("token", token);
}
return rb.buildPost();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
@Override
public String processAllReturningText(final String s) {
try {
if (token == null) {
Map<String, Object> result = new ObjectMapper().readValue(s, new TypeReference<HashMap<String,Object>>() {});
token = ((Map<String, String>)result.get("createaccount")).get("token");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return s;
}
@Override
public boolean hasMoreMessages() {
if (++count < 3) {
return true;
}
return false;
}
}
}