This commit is contained in:
R. Eric Wheeler 2016-12-20 14:32:00 -08:00
parent b641f863e8
commit 30f33f1f0c
20 changed files with 1523 additions and 137 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
/vendor/
*~
*~
.idea/

9
.idea/composerJson.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ComposerJsonPluginSettings">
<unboundedVersionInspectionSettings>
<excludedPackages />
</unboundedVersionInspectionSettings>
<customRepositories />
</component>
</project>

4
.idea/deployment.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" serverName="Symfony" />
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

19
.php_cs Normal file
View File

@ -0,0 +1,19 @@
<?php
$header = <<<'EOF'
This file is part of Selenium Tor Driver.
(c) R. Eric Wheeler <eric@rewiv.com>
This source file is subject to the MIT license that is bundled
with this source code in the file LICENSE.
EOF;
$finder = PhpCsFixer\Finder::create()
->in([__DIR__ . '/src', __DIR__ . '/Tests']);
return PhpCsFixer\Config::create()
->setRules([
'@PSR2' => true,
'header_comment' => [
'header' => $header
],
])
->setFinder($finder);

55
README.md Normal file
View File

@ -0,0 +1,55 @@
## Selenium Tor Implementation for [facebook/php-webdriver](https://github.com/facebook/php-webdriver)
### Usage
#### Install Composer
* `curl -SsL https://getcomposer.org/installer|php`
* `mv composer.phar /usr/local/bin/composer`
#### Get the code
* Clone the repository `git clone https://repos.bgemi.net/sikofitt/selenium-tor`
* `cd selenium-tor`
#### Install dependencies
* Then install the dependencies with `composer install`
#### Get tor if you don't have it
* `composer download` or
* `bin/console tor:download`
```php
use Sikofitt\WebDriver\FirefoxBinary;
use Sikofitt\WebDriver\Remote\DesiredCapabilities;
use Sikofitt\WebDriver\Tor\TorProfile;
use Sikofitt\WebDriver\TorLauncher;
require 'vendor/autoload.php';
$firefoxBinary = new FirefoxBinary(__DIR__ . '/../tor-browser_en-US/Browser/start-tor-browser');
$caps = DesiredCapabilities::tor($firefoxBinary);
$profile = new TorProfile();
$caps->setCapability('timeout', 3600);
$caps->setCapability(FirefoxDriver::PROFILE, $profile);
$torProcess = TorLauncher::launch($firefoxBinary);
// Wait for Tor to connect
sleep(2);
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $caps);
$this->webDriver->navigate()->to('http://32b5oz2bbtn6gqj3.onion');
// Or $this-webDriver->get('http://32b5oz2bbtn6gqj3.onion');
$pageImages = $this->webDriver->findElements(WebDriverBy::tagName('img'));
$images = [];
foreach($pageImages as $image)
{
$images[] = $image->getAttribute('src');
}
TorLauncher::stop($torProcess);
```
### Tests
`composer test'`

View File

@ -0,0 +1,28 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
use Sikofitt\WebDriver\FirefoxBinary;
/**
* Created by PhpStorm.
* User: eric
* Date: 12/20/16
* Time: 1:33 PM
*/
class FireFoxBinaryTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException \Exception
*/
public function testBinaryFail()
{
$fireFoxBinary = new FirefoxBinary('file');
}
}

View File

@ -1,25 +0,0 @@
<?php
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
require 'vendor/autoload.php';
class GitHubTests extends PHPUnit_Framework_TestCase {
protected $webDriver;
protected $url = 'https://github.com';
public function setUp() {
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', DesiredCapabilities::firefox());
}
public function tearDown()
{
$this->webDriver->quit();
}
public function testGitHubHome() {
$this->webDriver->get($this->url);
$this->assertContains('GitHub', $this->webDriver->getTitle());
}
}

View File

@ -0,0 +1,67 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
use Sikofitt\WebDriver\FirefoxBinary;
use Sikofitt\WebDriver\Remote\DesiredCapabilities;
use Sikofitt\WebDriver\Tor\TorProfile;
use Sikofitt\WebDriver\TorLauncher;
require 'vendor/autoload.php';
/**
* Class SeleniumTorTests
*/
class SeleniumTorSimpleTests extends PHPUnit_Framework_TestCase
{
protected $webDriver;
protected $urls = [
'http://skunksworkedp2cg.onion/sites.html' => 'A list of onion sites ordered by hostname',
'http://32b5oz2bbtn6gqj3.onion' => 'The Hidden Wiki',
];
protected $process;
protected $torProcess;
public function setUp()
{
$firefoxBinary = new FirefoxBinary(__DIR__ . '/../tor-browser_en-US/Browser/start-tor-browser');
$caps = DesiredCapabilities::tor($firefoxBinary);
$profile = new TorProfile();
$caps->setCapability('timeout', 3600);
$caps->setCapability(FirefoxDriver::PROFILE, $profile);
$this->torProcess = TorLauncher::launch($firefoxBinary);
// Wait for Tor to connect
sleep(2);
$this->webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub', $caps);
}
public function tearDown()
{
$this->webDriver->quit();
TorLauncher::stop($this->torProcess);
}
public function testOnionCoreSite()
{
foreach ($this->urls as $url => $title) {
$this->webDriver->navigate()->to($url);
$elements = $this->webDriver->findElements(WebDriverBy::tagName('img'));
$this->assertEquals($title, $this->webDriver->getTitle());
$images = [];
foreach ($elements as $element) {
$images[] = $element->getAttribute('src');
}
file_put_contents(__DIR__ . '/../' . 'data.json', json_encode($images, JSON_PRETTY_PRINT));
}
}
}

18
bin/console Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env php
<?php
/**
* Created by PhpStorm.
* User: eric
* Date: 12/20/16
* Time: 8:26 AM
*/
use Symfony\Component\Console\Application;
require __DIR__ . '/../vendor/autoload.php';
define('BASE_DIR', __DIR__ . '/../');
$app = new Application('Selenium tests', '0.0.1');
$app->add(new Sikofitt\Console\Command\TorBrowserDownloadCommand());
$app->run();

View File

@ -1,9 +1,22 @@
{
"require-dev": {
"phpunit/phpunit": "*",
"facebook/webdriver": "^1.2",
"se/selenium-server-standalone": "~2"
"friendsofphp/php-cs-fixer": "^2.0"
},
"require": {
"facebook/webdriver": "dev-master",
"se/selenium-server-standalone": "~2",
"guzzlehttp/guzzle": "^6.2",
"symfony/console": "^3.2",
"symfony/process": "^3.2"
},
"autoload": {
"psr-4": {
"Sikofitt\\":"src/Sikofitt"
}
},
"scripts": {
"tests": "vendor/bin/phpunit",
"download":"php bin/console tor:download"
}
}

1045
composer.lock generated

File diff suppressed because it is too large Load Diff

30
phpunit.xml Normal file
View File

@ -0,0 +1,30 @@
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
backupGlobals="true"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
cacheTokens="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
timeoutForSmallTests="3600"
timeoutForMediumTests="3600"
timeoutForLargeTests="3600"
verbose="true">
<testsuites>
<testsuite name="Selenium Tests">
<directory suffix=".php">Tests/</directory>
<exclude>src/</exclude>
<file>*.php</file>
</testsuite>
</testsuites>
</phpunit>

View File

@ -0,0 +1,139 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\Console\Command;
use GuzzleHttp\Client;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
/**
* Class TorBrowserDownloadCommand
*
* @package Sikofitt\Console\Command
*/
class TorBrowserDownloadCommand extends Command
{
const TOR_VERSION = '6.0.8';
const TOR_DOWNLOAD_URL = 'https://www.torproject.org/dist/torbrowser';
const TOR_PACKAGE_LINUX_I386 = 'tor-browser-linux32-6.0.8_en-US.tar.xz';
const TOR_PACKAGE_LINUX_X64 = 'tor-browser-linux64-6.0.8_en-US.tar.xz';
const TOR_PACKAGE_WIN = 'torbrowser-install-6.0.8_en-US.exe';
private $url;
/**
* {@inheritdoc}
*/
public function configure()
{
$this->setName('tor:download')
->setDescription('Downloads the tor browser.');
}
/**
* Downloads and extracts the tor browser.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
public function execute(InputInterface $input, OutputInterface $output)
{
$this->url = $this->getDownloadUrl();
$io = $this->getStyle($input, $output);
$download = $io->confirm('Download Tor?', true);
if (false === $download) {
exit(255);
}
$io->note('Downloading ' . $this->getDownloadUrl() . ' ...');
if (false === file_exists(BASE_DIR . $this->getFileName())) {
$client = new Client();
try {
$data = $client->get($this->url);
} catch (\Exception $e) {
$io->error($e->getMessage());
exit;
}
file_put_contents(BASE_DIR . $this->getFileName(), $data->getBody()->getContents());
}
$io->success('Downloaded');
$io->note('Extracting ...');
$tar = new ProcessBuilder();
$tar
->setPrefix('tar')
->setArguments(array('-xvf', BASE_DIR . $this->getFileName()))
->getProcess()->run();
}
/**
* Helper method to get symfony style
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* The Input instance
* @param \Symfony\Component\Console\Output\OutputInterface $output
* The output instance
*
* @return \Symfony\Component\Console\Style\SymfonyStyle
* Instance of SymfonyStyle
*/
private function getStyle(InputInterface $input, OutputInterface $output)
{
return new SymfonyStyle($input, $output);
}
private function getFileName()
{
$arch = $this->getArch();
$os = $this->getOS();
switch ($os) {
case 'linux':
default:
switch ($arch) {
case 'i386':
$package = self::TOR_PACKAGE_LINUX_I386;
break;
case 'x86_64':
default:
$package = self::TOR_PACKAGE_LINUX_X64;
break;
}
break;
case 'win':
case 'windows':
$package = self::TOR_PACKAGE_WIN;
break;
}
return $package;
}
private function getDownloadUrl()
{
$package = $this->getFileName();
return sprintf('%s/%s/%s', self::TOR_DOWNLOAD_URL, self::TOR_VERSION, $package);
}
private function getArch()
{
return strtolower(php_uname('m'));
}
private function getOS()
{
return strtolower(PHP_OS);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver;
use Symfony\Component\Process\Process;
/**
* Class FirefoxBinary
*
* @package Sikofitt\WebDriver
*/
class FirefoxBinary extends \SplFileInfo
{
/**
* @var string
*/
private $binaryName;
public function __construct($binaryName)
{
parent::__construct($binaryName);
$this->binaryName = $binaryName;
if (false === $this->isExecutable()) {
throw new \Exception(sprintf('%s is not executable.', $this->binaryName));
}
}
}

View File

@ -0,0 +1,37 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver\Remote;
use Sikofitt\WebDriver\FirefoxBinary;
use WebDriverCapabilityType;
use WebDriverPlatform;
use DesiredCapabilities as FaceBookDesiredCapabilities;
class DesiredCapabilities extends FaceBookDesiredCapabilities
{
/**
* @param FirefoxBinary|null $firefoxBinary
*
* @return static DesiredCapabilities
*/
public static function tor(FirefoxBinary $firefoxBinary = null)
{
$caps = new static([
WebDriverCapabilityType::BROWSER_NAME => 'firefox',
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
]);
if (null !== $firefoxBinary) {
$caps->setCapability('firefox_binary', $firefoxBinary->getPathname());
}
return $caps;
}
}

View File

@ -0,0 +1,17 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver\Tor;
use FirefoxDriver;
class TorDriver extends FirefoxDriver
{
const PROFILE = '/home/eric/projects/selenium-tor/tor-browser_en-US/Browser/TorBrowser/Data/Browser/profile.default';
}

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver\Tor;
/**
* Class TorPreferences
*
* @package Sikofitt\WebDriver\Tor
*/
class TorPreferences extends FirefoxPreferences
{
/**
* @var string
* Port WebDriver uses to communicate with Firefox instance
*/
const WEBDRIVER_FIREFOX_PORT = 'webdriver_firefox_port';
/**
* @var string
* Should the reader view (FF 38+) be enabled? NO.
* Disable the "Reader View" help tooltip, which can hide elements in the window.document
*/
const READER_PARSE_ON_LOAD_ENABLED = false;
/**
* @var string
* Browser homepage
*/
const BROWSER_STARTUP_HOMEPAGE = 'browser.startup.homepage';
private function __construct()
{
}
}

View File

@ -0,0 +1,16 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver\Tor;
use FirefoxProfile;
class TorProfile extends FirefoxProfile
{
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Selenium Tor Driver.
* (c) R. Eric Wheeler <eric@rewiv.com>
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sikofitt\WebDriver;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
class TorLauncher
{
public static function launch(FirefoxBinary $firefoxBinary, $options = [])
{
$defaultOptions = array(
'--detach',
'--browser',
'--new-instance',
'--allow-remote',
);
$defaultOptions += $options;
$processBuilder = new ProcessBuilder();
$processBuilder
->setPrefix($firefoxBinary->getPathname())
->setArguments($defaultOptions);
$process = $processBuilder->getProcess();
$process->start();
return $process;
}
public static function stop(Process $process)
{
$process->stop(3, SIGKILL);
if ('linux' === strtolower(PHP_OS)) {
$processBuilder = new ProcessBuilder();
$processBuilder->setPrefix('killall')
->setArguments(['firefox'])
->getProcess()
->run();
}
}
}