/*
Copyright (c) Microsoft Open Technologies, Inc.
All Rights Reserved
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
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache 2 License for the specific language governing permissions and limitations under the License.
*/
package com.msopentech.thali.toronionproxy;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* This class encapsulates data that is handled differently in Java and Android
* as well as managing file locations.
*/
abstract public class OnionProxyContext {
protected final static String hiddenserviceDirectoryName = "hiddenservice";
protected final static String geoIpName = "geoip";
protected final static String geoIpv6Name = "geoip6";
protected final static String torrcName = "torrc";
protected final File workingDirectory;
protected final File geoIpFile;
protected final File geoIpv6File;
protected final File torrcFile;
protected final File torExecutableFile;
protected final File cookieFile;
protected final File hostnameFile;
public OnionProxyContext(File workingDirectory) {
this.workingDirectory = workingDirectory;
geoIpFile = new File(getWorkingDirectory(), geoIpName);
geoIpv6File = new File(getWorkingDirectory(), geoIpv6Name);
torrcFile = new File(getWorkingDirectory(), torrcName);
torExecutableFile = new File(getWorkingDirectory(), getTorExecutableFileName());
cookieFile = new File(getWorkingDirectory(), ".tor/control_auth_cookie");
hostnameFile = new File(getWorkingDirectory(), "/" + hiddenserviceDirectoryName + "/hostname");
}
protected void installFiles() throws IOException, InterruptedException {
// This is sleezy but we have cases where an old instance of the Tor OP
// needs an extra second to
// clean itself up. Without that time we can't do things like delete its
// binary (which we currently
// do by default, something we hope to fix with
// https://github.com/thaliproject/Tor_Onion_Proxy_Library/issues/13
Thread.sleep(1000, 0);
if (getWorkingDirectory().listFiles() != null) {
for (File f : getWorkingDirectory().listFiles()) {
if (f.getAbsolutePath().startsWith(torrcFile.getAbsolutePath())) {
f.delete();
}
}
}
try {
File dotTorDir = new File(getWorkingDirectory(), ".tor");
if (dotTorDir.exists())
FileUtilities.recursiveFileDelete(dotTorDir);
} catch (Exception e) {
}
if (workingDirectory.exists() == false && workingDirectory.mkdirs() == false) {
throw new RuntimeException("Could not create root directory!");
}
FileUtilities.cleanInstallOneFile(getAssetOrResourceByName(geoIpName), geoIpFile);
FileUtilities.cleanInstallOneFile(getAssetOrResourceByName(geoIpv6Name), geoIpv6File);
FileUtilities.cleanInstallOneFile(getAssetOrResourceByName(torrcName), torrcFile);
}
/**
* Sets environment variables and working directory needed for Tor
*
* @param processBuilder we will call start on this to run Tor
*/
void setEnvironmentArgsAndWorkingDirectoryForStart(ProcessBuilder processBuilder) {
processBuilder.directory(getWorkingDirectory());
Map<String, String> environment = processBuilder.environment();
environment.put("HOME", getWorkingDirectory().getAbsolutePath());
switch (OsData.getOsType()) {
case Linux32:
case Linux64:
// We have to provide the LD_LIBRARY_PATH because when looking
// for dynamic libraries
// Linux apparently will not look in the current directory by
// default. By setting this
// environment variable we fix that.
environment.put("LD_LIBRARY_PATH", getWorkingDirectory().getAbsolutePath());
default:
break;
}
}
public String[] getEnvironmentArgsForExec() {
List<String> envArgs = new ArrayList<String>();
envArgs.add("HOME=" + getWorkingDirectory().getAbsolutePath());
switch (OsData.getOsType()) {
case Linux32:
case Linux64:
// We have to provide the LD_LIBRARY_PATH
envArgs.add("LD_LIBRARY_PATH=" + getWorkingDirectory().getAbsolutePath());
default:
break;
}
return envArgs.toArray(new String[envArgs.size()]);
}
public File getGeoIpFile() {
return geoIpFile;
}
public File getGeoIpv6File() {
return geoIpv6File;
}
public File getTorrcFile() {
return torrcFile;
}
public File getCookieFile() {
return cookieFile;
}
public File getHostNameFile() {
return hostnameFile;
}
public File getTorExecutableFile() {
return torExecutableFile;
}
public File getWorkingDirectory() {
return workingDirectory;
}
void deleteAllFilesButHiddenServices() throws InterruptedException {
// It can take a little bit for the Tor OP to detect the connection is
// dead and kill itself
Thread.sleep(1000);
for (File file : getWorkingDirectory().listFiles()) {
if (file.isDirectory()) {
if (file.getName().compareTo(hiddenserviceDirectoryName) != 0) {
FileUtilities.recursiveFileDelete(file);
}
} else {
if (file.delete() == false) {
throw new RuntimeException("Could not delete file " + file.getAbsolutePath());
}
}
}
}
/**
* Files we pull out of the AAR or JAR are typically at the root but for
* executables outside of Android the executable for a particular platform
* is in a specific sub-directory.
*
* @return Path to executable in JAR Resources
*/
protected abstract String getPathToTorExecutable();
protected abstract String getTorExecutableFileName();
abstract public String getProcessId();
abstract public WriteObserver generateWriteObserver(File file);
abstract protected InputStream getAssetOrResourceByName(String fileName) throws IOException;
public File getHiddenServiceDirectory() {
return new File(getWorkingDirectory(), "/" + hiddenserviceDirectoryName);
}
}