You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

722 lines
22 KiB
Java

/*
* Copyright (C) 2009-2017 Alistair Neil <info@dazzleships.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package client;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import lib.OSFunction;
import lib.SimpleFile;
/**
*
* @author Alistair Neil <info@dazzleships.net>
*/
public class PacFactory {
public static final String FILEUSER = "user";
private static final String FILEEXT = ".txt";
public static final int PROXY_DISABLED = 0;
public static final int PROXY_PATTERN = 1;
public static final int PROXY_ALL = 2;
private static final String PACFILE_EXT = ".pac";
private static final String PATTERNFIRSTLINE = "### Pattern File, Do not remove or modify this line ###";
private String strKDEProxyPrefsBackup;
private String strGnome3ProxyPrefsBackup;
private String strPACPath;
private String strBackupFolder;
private String strPatternsFolder;
private String strTempFolder;
private String strDefaultProxy = "";
private String strDoNotProxy = "";
private String strActiveCountry;
private String strActivePacName = "";
private final Random randgen;
public PacFactory() {
randgen = new Random(System.currentTimeMillis());
}
/**
* Get the active country code
*
* @return Active country
*/
public String getActiveCountry() {
return strActiveCountry;
}
/**
* Create and/or activate a pacfile for a specific country
*
* @param isocountry
* @param port
*/
public void createPacFile(String isocountry, int port) {
// Generate a pseudo random pac name
String pacname = createRandomName() + PACFILE_EXT;
savePACFile(pacname, getPacRules(isocountry, String.valueOf(port)));
setProxyAutoConfigURL("file://" + strPACPath.replace("\\", "/") + pacname);
strActiveCountry = isocountry;
if (!strActivePacName.isEmpty()) {
this.deletePAC(strActivePacName);
}
strActivePacName = pacname;
}
/**
* Get pac rules for a specific country Can also be used for getting direct
* rule and proxy all rules, by setting countrycode to "direct" or
* "proxyall"
*
* @param countrycode
* @param port
* @return An arraylist of rules
*/
private ArrayList<String> getPacRules(String country, String port) {
ArrayList<String> result = new ArrayList<>();
// If country code is null then generate proxy all traffic rules
if (country.contentEquals("proxyall")) {
addSocksRule(result, "127.0.0.1", port);
return result;
}
if (country.contentEquals("direct")) {
addDirectMatchingRule(result, null);
return result;
}
Pattern pat = Pattern.compile(",");
String[] split;
// Create our pattern rules storage list
ArrayList<String> patternrules = new ArrayList<>();
// Add in do not proxy rules
if (!strDoNotProxy.isEmpty()) {
split = pat.split(strDoNotProxy);
for (String s : split) {
if (!s.isEmpty()) {
addDirectMatchingRule(result, "*" + s + "*");
}
}
}
// Get default patterns
loadPatternsList(country, patternrules);
for (String s : patternrules) {
split = pat.split(s);
if (split.length < 3) {
break;
}
if (split[2].contentEquals("true")) {
if (split[1].contentEquals("*")) {
addSocksRule(result, "127.0.0.1", port);
return result;
} else {
addSocksMatchingRule(result, split[1], "127.0.0.1", port);
}
}
}
if (strDefaultProxy.isEmpty()) {
addDirectMatchingRule(result, null);
} else {
addProxyRule(result, strDefaultProxy);
}
return result;
}
/**
*
* @param rules
* @param proxy
*/
public void addProxyRule(ArrayList<String> rules, String proxy) {
rules.add("\treturn \"PROXY " + proxy + "\";");
}
/**
* Add a socks rule to a supplied list
*
* @param rules
* @param host
* @param port
*/
public void addSocksRule(ArrayList<String> rules, String host, String port) {
String rule = "\treturn \"SOCKS5 " + host + ":" + port + "\";";
rules.add(rule);
}
/**
*
* @param rules
* @param pattern
*/
public void addDirectMatchingRule(ArrayList<String> rules, String pattern) {
String rule;
if (pattern == null) {
rule = "\treturn \"DIRECT\";";
} else {
rule = "\tif (shExpMatch(url, \"" + pattern + "\"))\n"
+ "\t{\n"
+ "\t\treturn \"DIRECT\";\n"
+ "\t}";
}
rules.add(rule);
}
/**
* Add socks pattern mayching rule to a supllied list
*
* @param rules
* @param pattern
* @param host
* @param port
*/
public void addSocksMatchingRule(ArrayList<String> rules, String pattern, String host, String port) {
String rule = "\tif (shExpMatch(url, \"" + pattern + "\"))\n"
+ "\t{\n"
+ "\t\treturn \"SOCKS5 " + host + ":" + port + "\";\n"
+ "\t}";
rules.add(rule);
}
/**
* Load a patterns list from a file
*
* @param country
* @param list
*/
public void loadPatternsList(String country, ArrayList<String> list) {
String line;
int idxs, idxe;
SimpleFile sfPatternFile = new SimpleFile(strPatternsFolder + country.substring(0, 2) + "_" + FILEUSER + FILEEXT);
if (sfPatternFile.exists()) {
sfPatternFile.openBufferedRead();
while ((line = sfPatternFile.readLine()) != null) {
idxs = line.indexOf('<');
idxe = line.indexOf('>');
if (idxs == 0 && idxe == (line.length() - 1)) {
list.add(line.substring(idxs + 1, idxe) + "," + FILEUSER);
}
}
sfPatternFile.closeFile();
}
}
/**
* Delete patterns file for a given country and type, where type is either
* "def" or "user"
*
* @param country
* @param type
*/
public void deletePatternsFile(String country, String type) {
SimpleFile sfPatternFile = new SimpleFile(strPatternsFolder + country.substring(0, 2) + "_" + type + FILEEXT);
sfPatternFile.delete();
}
/**
* Save a patterns list by filename
*
* @param country
* @param list
* @param type
*/
public void savePatternsList(String country, String type, ArrayList<String> list) {
SimpleFile sfPatternFile = new SimpleFile(strPatternsFolder + country.substring(0, 2) + "_" + type + FILEEXT);
sfPatternFile.openBufferedWrite();
sfPatternFile.writeFile(PATTERNFIRSTLINE, 1);
for (String s : list) {
sfPatternFile.writeFile("<" + s + ">", 1);
}
sfPatternFile.closeFile();
}
/**
* Create folder in which pattern files will be stored
*
* @param folder
*/
public final void setPatternsFolder(String folder) {
strPatternsFolder = folder + SimpleFile.getSeparator();
SimpleFile.createFolder(strPatternsFolder);
}
/**
* Set folder where pac files will be generated
*
* @param folder
*/
public final void setPACFolder(String folder) {
strPACPath = folder;
SimpleFile.createFolder(folder);
}
/**
* Set folder where system proxy settings will be backed up
*
* @param folder
*/
public final void setBackupFolder(String folder) {
strBackupFolder = folder + SimpleFile.getSeparator();
SimpleFile.createFolder(strBackupFolder);
if (OSFunction.getGsettingsPath() != null) {
strGnome3ProxyPrefsBackup = strBackupFolder + "gnome3_proxy.txt";
} else {
strGnome3ProxyPrefsBackup = null;
}
if (OSFunction.getKDEProxyPath() != null) {
strKDEProxyPrefsBackup = strBackupFolder + "kde_proxy.txt";
} else {
strKDEProxyPrefsBackup = null;
}
}
/**
* Set the temp folder for file extractions
*
* @param path
*/
public final void setTempFolder(String path) {
strTempFolder = path;
}
/**
* Generic backup of proxy settings
*
*/
public void backupProxyPrefs() {
backupGnomeProxyPrefs();
backupKDEProxyPrefs();
}
/**
* Gnome backup of proxy settings
*
*/
private void backupGnomeProxyPrefs() {
if (strBackupFolder == null) {
return;
}
SimpleFile sfProxyPrefs;
try {
if (strGnome3ProxyPrefsBackup != null) {
sfProxyPrefs = new SimpleFile(strGnome3ProxyPrefsBackup);
if (!sfProxyPrefs.exists()) {
sfProxyPrefs.openBufferedWrite();
sfProxyPrefs.writeFile(OSFunction.getGnome3Pref("org.gnome.system.proxy", "mode"), 1);
sfProxyPrefs.writeFile(OSFunction.getGnome3Pref("org.gnome.system.proxy", "autoconfig-url"), 1);
sfProxyPrefs.closeFile();
}
}
} catch (Exception ex) {
Logger.getGlobal().logp(Level.SEVERE, this.getClass().getName(), "backupGnomeProxyPrefs()", "", ex);
}
}
/**
* KDE backup of proxy settings
*
*/
private void backupKDEProxyPrefs() {
if (strBackupFolder == null) {
return;
}
SimpleFile sfProxyPrefs;
try {
if (strKDEProxyPrefsBackup != null) {
sfProxyPrefs = new SimpleFile(strKDEProxyPrefsBackup);
if (!sfProxyPrefs.exists()) {
sfProxyPrefs.openBufferedWrite();
sfProxyPrefs.writeFile(OSFunction.getKDEPref("Proxy Settings", "Proxy Config Script", ""), 1);
sfProxyPrefs.writeFile(OSFunction.getKDEPref("Proxy Settings", "ProxyType", "0"), 1);
sfProxyPrefs.closeFile();
}
}
} catch (Exception ex) {
Logger.getGlobal().logp(Level.SEVERE, this.getClass().getName(), "backupKDEProxyPrefs()", "", ex);
}
}
/**
* Generic restore of proxy settings, for ease of use
*
*/
public void restoreProxyPrefs(boolean resetonfail) {
restoreGnomeProxyPrefs(resetonfail);
restoreKDEProxyPrefs(resetonfail);
}
/**
* Gnome specific restore of proxy settings
*
*/
private void restoreGnomeProxyPrefs(boolean resetonfail) {
SimpleFile sfProxyPrefs;
try {
// Restore gnome3 proxy prefs
if (strGnome3ProxyPrefsBackup != null) {
sfProxyPrefs = new SimpleFile(strGnome3ProxyPrefsBackup);
if (sfProxyPrefs.exists()) {
sfProxyPrefs.openBufferedRead();
String mode = sfProxyPrefs.readLine();
String url = sfProxyPrefs.readLine();
sfProxyPrefs.closeFile();
if (url != null && mode != null && !mode.isEmpty()) {
// Restore original settings from file
OSFunction.setGnome3Pref("org.gnome.system.proxy", "mode", mode);
OSFunction.setGnome3Pref("org.gnome.system.proxy", "autoconfig-url", url);
}
} else {
if (resetonfail) {
setGnomeProxyAutoConfigURL(null);
}
}
}
} catch (Exception ex) {
Logger.getGlobal().logp(Level.SEVERE, this.getClass().getName(), "restoreGnomeProxyPrefs()", "", ex);
}
}
/**
* KDE specific restore of proxy settings
*
*/
private void restoreKDEProxyPrefs(boolean resetonfail) {
SimpleFile sfProxyPrefs;
try {
// Restore kde proxy prefs
if (strKDEProxyPrefsBackup != null) {
sfProxyPrefs = new SimpleFile(strKDEProxyPrefsBackup);
if (sfProxyPrefs.exists()) {
sfProxyPrefs.openBufferedRead();
String url = sfProxyPrefs.readLine();
String type = sfProxyPrefs.readLine();
sfProxyPrefs.closeFile();
if (url != null && type != null) {
if (!SimpleFile.exists(url)) {
url = "";
}
OSFunction.setKDEPref("Proxy Settings", "Proxy Config Script", url);
OSFunction.setKDEPref("Proxy Settings", "ProxyType", type);
}
} else {
if (resetonfail) {
setKDEProxyAutoConfigURL(null);
}
}
}
} catch (Exception ex) {
Logger.getGlobal().logp(Level.SEVERE, this.getClass().getName(), "restoreKDEProxyPrefs()", "", ex);
}
}
/**
* Generic proxy prefs delete, for ease of use
*/
public void deleteProxyPrefs() {
deleteGnomeProxyPrefs();
deleteKDEProxyPrefs();
}
/**
* Generic delete of backed up gnome proxy settings
*
* @return boolean True if successful
*/
private boolean deleteGnomeProxyPrefs() {
if (strBackupFolder == null) {
return false;
}
boolean result = true;
// Delete Gnome3 prefs
if (strGnome3ProxyPrefsBackup != null) {
result = SimpleFile.delete(strGnome3ProxyPrefsBackup);
}
return result;
}
/**
* Generic delete of backed up KDE proxy settings
*
* @return boolean True if successful
*/
private boolean deleteKDEProxyPrefs() {
if (strBackupFolder == null) {
return false;
}
boolean result = true;
// Delete Kde prefs
if (strKDEProxyPrefsBackup != null) {
result = SimpleFile.delete(strKDEProxyPrefsBackup);
}
return result;
}
/**
* Generic set proxy config
*
* @param url
*/
public void setProxyAutoConfigURL(String url) {
setGnomeProxyAutoConfigURL(url);
setKDEProxyAutoConfigURL(url);
}
/**
* Set Gnome proxy config
*
* @param url
*/
private void setGnomeProxyAutoConfigURL(String url) {
if (strGnome3ProxyPrefsBackup != null) {
if (url == null) {
OSFunction.resetGnome3Pref("org.gnome.system.proxy", "mode");
OSFunction.resetGnome3Pref("org.gnome.system.proxy", "autoconfig-url");
} else {
OSFunction.setGnome3Pref("org.gnome.system.proxy", "mode", "auto");
OSFunction.setGnome3Pref("org.gnome.system.proxy", "autoconfig-url", url);
}
}
}
/**
* Set KDE proxy config
*
* @param url
*/
private void setKDEProxyAutoConfigURL(String url) {
if (strKDEProxyPrefsBackup != null) {
if (url == null) {
OSFunction.setKDEPref("Proxy Settings", "Proxy Config Script", "");
OSFunction.setKDEPref("Proxy Settings", "ProxyType", 0);
} else {
OSFunction.setKDEPref("Proxy Settings", "Proxy Config Script", url);
OSFunction.setKDEPref("Proxy Settings", "ProxyType", 2);
}
}
}
/**
* Save pac file using given filename
*
* @param filename
* @param ruleslist
*/
private void savePACFile(String filename, ArrayList<String> ruleslist) {
SimpleFile sfPacFile = new SimpleFile(strPACPath + filename);
sfPacFile.openBufferedWrite();
sfPacFile.writeFile("//" + filename, 1);
String temp = "function FindProxyForURL(url, host) {";
sfPacFile.writeFile(temp, 1);
for (String s : ruleslist) {
sfPacFile.writeFile(s, 1);
}
sfPacFile.writeFile("}", 1);
sfPacFile.closeFile();
}
/**
* Delete specified pac file
*
* @param filename
* @return boolean true if action successful
*/
public boolean deletePAC(String filename) {
return SimpleFile.delete(strPACPath + filename);
}
/**
* Delete all pac files
*/
public void deleteAllPAC() {
SimpleFile sf = new SimpleFile(strPACPath);
sf.setFileFilter(PACFILE_EXT);
sf.deleteFileList(sf.getFileList());
}
/**
* Get a pseudo random numerical name
*
* @return String
*/
private String createRandomName() {
// Create new filename with a random number to modify filename from
// previous one to force auto reload of pac settings in browser
int pacNumber = randgen.nextInt();
if (pacNumber < 0) {
pacNumber = 0 - pacNumber;
}
return String.valueOf(pacNumber);
}
/**
* Set default proxy url
*
* @param proxyurl
*/
public void setDefaultProxy(String proxyurl) {
strDefaultProxy = proxyurl;
}
/**
* Set do not proxy
*
* @param hostcsv
*/
public void setDoNotProxy(String hostcsv) {
strDoNotProxy = hostcsv;
}
/**
* Get value of comma separated host or ip list
*
* @return String value
*/
public String getDoNotProxy() {
return strDoNotProxy;
}
/**
* Adds pattern to an existing pattern file
*
* @param country
* @param description
* @param pattern
*/
public void addToPatternFile(String country, String description, String pattern) {
if (strPatternsFolder == null || pattern.isEmpty()) {
return;
}
SimpleFile sfPatternFile = new SimpleFile(strPatternsFolder + SimpleFile.getSeparator() + country.substring(0, 2) + "_" + FILEUSER + FILEEXT);
sfPatternFile.openBufferedAppend();
sfPatternFile.writeFile("<" + description + "," + pattern + ",true>", 1);
sfPatternFile.closeFile();
}
/**
* Get an array of user pattern files
*
* @return array of files
*/
public File[] getPatternsFiles() {
SimpleFile sf = new SimpleFile(strPatternsFolder);
sf.setFileFilter(FILEUSER + FILEEXT);
return sf.getFileList();
}
/**
* Export user patterns
*
* @param filename
* @param files
*/
public void exportUserPatterns(String filename, File[] files) {
// Append .zip extension if we need to
if (!filename.endsWith(".zip")) {
filename += ".zip";
}
// Add user pattern files to zip
SimpleFile sf = new SimpleFile(filename);
sf.openZipStream(9);
sf.addFilesToZip(files);
sf.closeZipStream();
}
/**
* Import patterns
*
* @param filename
* @return true if succesful
*/
public boolean importPatterns(String filename) {
// Import patterns
boolean success = false;
SimpleFile sf = new SimpleFile(filename);
String destpath;
// Check existence
if (sf.exists()) {
// Get temporary path to extraction folder
if (strTempFolder == null) {
destpath = OSFunction.getTempFolder(null)
+ getClass().getName();
} else {
destpath = strTempFolder + getClass().getName();
}
// Create temp extraction folder
SimpleFile.createFolder(destpath);
// Extract files to temp folder
success = sf.extractZipTo(destpath);
if (success) {
// Get list of files
sf.setFileName(destpath);
sf.setFileFilter(".txt");
File[] files = sf.getFileList();
// Verify each file before copying them over
String firstLine;
try {
if (files.length == 0) {
throw new Exception();
}
for (File f : files) {
// Verify valid pattern file by checking first line of file
sf.setFile(f);
sf.openBufferedRead();
firstLine = sf.readLine();
sf.closeFile();
if (firstLine != null) {
if (firstLine.toLowerCase().contains("pattern file")) {
SimpleFile.copyFromTo(f.getAbsolutePath(), strPatternsFolder + f.getName());
} else {
success = false;
break;
}
}
}
} catch (Exception ex) {
success = false;
}
}
// Delete temporary files
SimpleFile.deleteFolder(destpath);
}
return success;
}
}