Inital commit

This commit is contained in:
Daniel Winzen
2016-08-19 10:05:50 +02:00
commit 08f666941e
13 changed files with 1359 additions and 0 deletions

31
README Normal file
View File

@ -0,0 +1,31 @@
GENERAL INFORMATION:
This is a set of script to list TOR hidden services. An up-to-date copy can be downloaded at https://github.com/DanWin/onion-link-list
INSTALLATION INSTRUCTIONS:
You'll need to have php with pdo_mysql, pcre, json and date extension, a web-server and a MySQL server installed.
When you have everything installed, you'll have to create a database and a user for the script.
Then edit the configuration in common_config.php to reflect the appropriate database settings and to modify the settings the way you like them.
Then copy the scripts to your web-server directory and open the setup.php script like this: http://(server)/setup.php
Note: If you updated the script, please visit http://(server)/setup.php again, to make sure, that any database changes are applied and no errors occure.
At last set up cron jobs for update.php phishing_tests.php and background_tests.php
Recommended schedule:
update.php - every 24 hours
phishing_tests.php - every 24 hours, shortly after update.php
background_tests.php - every 15 minutes
TRANSLATING:
Copy lang_en.php and rename it to lang_YOUR_LANGCODE.php
Then edit the file and translate the messages into your language and change $I to $T at the top.
If you ever use a ' character, you have to escape it by using \' instead or the script will fail.
When you are done, you have to edit common_config.php, to include your translation. Simply add a line with
'lang_code' => 'Language name',
to the $L array below the settings, similar to what I did for the German translation.
Please share your translation with me, so I can add it to the official version.
To update your translation, you can copy each new string to your translation file or edit the automated lang_update.php script to reflect you language and run it.
LIVE DEMO:
If you want to see the scripts in action, you can visit my TOR hidden service http://tt3j2x4k5ycaa5zt.onion/onions.php or via a tor2web proxy like http://tt3j2x4k5ycaa5zt.onion.to/onions.php if you don't have TOR installed.

39
README.md Normal file
View File

@ -0,0 +1,39 @@
General information:
--------------------
This is a set of script to list TOR hidden services. An up-to-date copy can be downloaded at https://github.com/DanWin/onion-link-list
Installation instructions:
--------------------------
You'll need to have php with pdo_mysql, pcre, json and date extension, a web-server and a MySQL server installed.
When you have everything installed, you'll have to create a database and a user for the script.
Then edit the configuration in common_config.php to reflect the appropriate database settings and to modify the settings the way you like them.
Then copy the scripts to your web-server directory and open the setup.php script like this: ```http://(server)/setup.php```
Note: If you updated the script, please visit ```http://(server)/setup.php``` again, to make sure, that any database changes are applied and no errors occure.
At last, set up cron jobs for update.php phishing_tests.php and background_tests.php
Recommended schedule:
update.php - every 24 hours
phishing_tests.php - every 24 hours, shortly after update.php
background_tests.php - every 15 minutes
Translating:
------------
Copy lang_en.php and rename it to lang_YOUR_LANGCODE.php
Then edit the file and translate the messages into your language and change $I to $T at the top.
If you ever use a ' character, you have to escape it by using \' instead or the script will fail.
When you are done, you have to edit common_config.php, to include your translation. Simply add a line with
```'lang_code' => 'Language name',```
to the $L array below the settings, similar to what I did for the German translation.
Please share your translation with me, so I can add it to the official version.
To update your translation, you can copy each new string to your translation file or edit the automated lang_update.php script to reflect you language and run it.
Live Demo:
----------
If you want to see the scripts in action, you can visit my TOR hidden service http://tt3j2x4k5ycaa5zt.onion/onions.php or via a tor2web proxy like http://tt3j2x4k5ycaa5zt.onion.to/onions.php if you don't have TOR installed.

205
admin.php Normal file
View File

@ -0,0 +1,205 @@
<?php
/*
* Onion Link List - Admin interface
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
header('Content-Type: text/html; charset=UTF-8');
if($_SERVER['REQUEST_METHOD']==='HEAD'){
exit; // headers sent, no further processing needed
}
include('common_config.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
die($I['nodb']);
}
asort($categories);
echo '<!DOCTYPE html><html><head>';
echo "<title>$I[admintitle]</title>";
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<style type="text/css">.red{color:red;} .green{color:green;}</style>';
echo '</head><body>';
echo "<h2>$I[admintitle]</h2>";
print_langs();
//check password
if(!isSet($_POST['pass']) || $_POST['pass']!==ADMINPASS){
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\">";
echo "<input type=\"hidden\" name=\"lang\" value=\"$language\">";
echo "<p>$I[password]: <input type=\"password\" name=\"pass\" size=\"30\" required></p>";
echo "<input type=\"submit\" name=\"action\" value=\"$I[login]\">";
echo '</form>';
if(isSet($_POST['pass'])){
echo "<p class=\"red\">$I[wrongpass]</p>";
}
}else{
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\">";
echo "<input type=\"hidden\" name=\"lang\" value=\"$language\">";
echo "<input type=\"hidden\" name=\"pass\" value=\"$_POST[pass]\">";
echo "<p>$I[link]: <input name=\"addr\" size=\"30\" value=\"";
if(isSet($_REQUEST['addr'])){
echo htmlspecialchars($_REQUEST['addr']);
}
echo '" required></p>';
echo "<p>$I[cloneof]: <input type=\"text\" name=\"original\" size=\"30\"";
if(isSet($_REQUEST['original'])){
echo ' value="'.htmlspecialchars($_REQUEST['original']).'"';
}
echo '></p>';
echo "<p>$I[bitcoins]: <input type=\"text\" name=\"btc\" size=\"30\"";
if(isSet($_REQUEST['btc'])){
echo ' value="'.htmlspecialchars($_REQUEST['btc']).'"';
}
echo '></p>';
echo "<p>$I[adddesc]: <br><textarea name=\"desc\" rows=\"2\" cols=\"30\">";
if(!empty($_REQUEST['desc'])){
echo htmlspecialchars(trim($_REQUEST['desc']));
}elseif(isSet($_REQUEST['addr'])){
if(preg_match('~(^(https?://)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', trim($_REQUEST['addr']), $addr)){
$addr=strtolower($addr[3]);
$md5=md5($addr, true);
$stmt=$db->prepare('SELECT description, category FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute([$md5]);
if($desc=$stmt->fetch(PDO::FETCH_ASSOC)){
$category=$desc['category'];
echo str_replace('<br>', "\n", $desc['description']);
}
}
}
echo '</textarea></p>';
if(isSet($_REQUEST['cat']) && $_REQUEST['cat']<count($categories) && $_REQUEST['cat']>=0){
$category=$_REQUEST['cat'];
}
if(!isSet($category)){
$category=count($categories);
}
echo "<p>$I[category]: <select name=\"cat\">";
foreach($categories as $cat=>$name){
echo "<option value=\"$cat\"";
if($category==$cat || ($cat===0 && $category>=count($categories))){
echo ' selected';
}
echo ">$name</option>";
}
echo '</select></p>';
echo '<input style="display:none;" type="submit" name="action" value="None">';
echo '<table><tr>';
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[remove]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[lock]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[promote]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[phishing]\"></td>";
echo '</tr><tr>';
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[readd]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[unlock]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[unpromote]\"></td>";
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[unphishing]\"></td>";
echo '</tr><tr>';
echo "<td><input type=\"submit\" name=\"action\" value=\"$I[update]\"></td>";
echo '</tr></table>';
echo '</form><br>';
if(!empty($_POST['addr'])){
if(!preg_match('~(^(https?://)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', trim($_POST['addr']), $addr)){
echo "<p class=\"red\">$I[invalonion]</p>";
}else{
$addr=strtolower($addr[3]);
$md5=md5($addr, true);
if($_POST['action']===$I['remove']){ //remove address from public display
$db->prepare('UPDATE ' . PREFIX . "onions SET address='', locked=1 WHERE md5sum=?;")->execute([$md5]);
echo "<p class=\"green\">$I[succremove]</p>";
}elseif($_POST['action']===$I['lock']){ //lock editing
$db->prepare('UPDATE ' . PREFIX . 'onions SET locked=1 WHERE md5sum=?;')->execute([$md5]);
echo "<p class=\"green\">$I[succlock]</p>";
}elseif($_POST['action']===$I['readd']){ //add onion back, if previously removed
$db->prepare('UPDATE ' . PREFIX . 'onions SET address=?, locked=1 WHERE md5sum=?;')->execute([$addr, $md5]);
echo "<p class=\"green\">$I[succreadd]</p>";
}elseif($_POST['action']===$I['unlock']){ //unlock editing
$db->prepare('UPDATE ' . PREFIX . 'onions SET locked=0 WHERE md5sum=?;')->execute([$md5]);
echo "<p class=\"green\">$I[succunlock]</p>";
}elseif($_POST['action']===$I['promote']){ //promote link for payed time
$stmt=$db->prepare('SELECT special FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute([$md5]);
$specialtime=$stmt->fetch(PDO::FETCH_NUM);
if($specialtime[0]<time()){
$time=time()+(($_POST['btc']/PROMOTEPRICE)*PROMOTETIME);
}else{
$time=$specialtime[0]+(($_POST['btc']/PROMOTEPRICE)*PROMOTETIME);
}
$db->prepare('UPDATE ' . PREFIX . 'onions SET special=?, locked=1 WHERE md5sum=?;')->execute([$time, $md5]);
printf("<p class=\"green\">$I[succpromote]</p>", date('Y-m-d H:i', $time));
}elseif($_POST['action']===$I['unpromote']){ //remove promoted status
$db->prepare('UPDATE ' . PREFIX . 'onions SET special=0 WHERE md5sum=?;')->execute([$md5]);
echo "<p class=\"green\">$I[succunpromote]</p>";
}elseif($_POST['action']===$I['update']){ //update description
$stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute([$md5]);
if($category===count($categories)){
$category=0;
}
if(!isSet($_POST['desc'])){
$desc='';
}else{
$desc=trim($_POST['desc']);
$desc=htmlspecialchars($desc);
$desc=preg_replace("/(\r?\n|\r\n?)/", '<br>', $desc);
}
if(!$stmt->fetch(PDO::FETCH_ASSOC)){ //not yet there, add it
$stmt=$db->prepare('INSERT INTO ' . PREFIX . 'onions (address, description, md5sum, category, timeadded) VALUES (?, ?, ?, ?, ?);');
$stmt->execute([$addr, $desc, $md5, $category, time()]);
echo "<p class=\"green\">$I[succadd]</p>";
}elseif($desc!=''){ //update description+category
$stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET description=?, category=?, locked=1 WHERE md5sum=?;');
$stmt->execute([$desc, $category, $md5]);
echo "<p class=\"green\">$I[succupddesc]</p>";
}elseif($category!=0){ //only update category
$stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET category=? WHERE md5sum=?;');
$stmt->execute([$category, $md5]);
echo "<p class=\"green\">$I[succupdcat]!</p>";
}else{ //no description or category change and already known
echo "<p class=\"green\">$I[alreadyknown]</p>";
}
}elseif($_POST['action']===$I['phishing']){//mark as phishing clone
if($_POST['original']!=='' && !preg_match('~(^(https?://)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', $_POST['original'], $orig)){
echo "<p class=\"red\">$I[invalonion]</p>";
}else{
if(isset($orig[3])){
$orig=strtolower($orig[3]);
}else{
$orig='';
}
if($orig!==$addr){
$stmt=$db->prepare('INSERT INTO ' . PREFIX . 'phishing (onion_id, original) VALUES ((SELECT id FROM ' . PREFIX . 'onions WHERE address=?), ?);');
$stmt->execute([$addr, $orig]);
echo "<p class=\"green\">$I[succaddphish]</p>";
}else{
echo "<p class=\"red\">$I[samephish]</p>";
}
}
}elseif($_POST['action']===$I['unphishing']){ //remove phishing clone status
$stmt=$db->prepare('DELETE FROM ' . PREFIX . 'phishing WHERE onion_id=(SELECT id FROM ' . PREFIX . 'onions WHERE address=?);');
$stmt->execute([$addr]);
echo "<p class=\"green\">$I[succrmphish]</p>";
}else{ //no specific button was pressed
echo "<p class=\"red\">$I[noaction]</p>";
}
}
}
}
echo '<br><p style="text-align:center;font-size:small;"><a target="_blank" href="https://github.com/DanWin/onion-link-list">Onion Link List - ' . VERSION . '</a></p>';
echo '</body></html>';
?>

80
background_tests.php Normal file
View File

@ -0,0 +1,80 @@
<?php
/*
* Onion Link List - Automated up/down tests
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// Executed every 15 minutes via cron - up/down checks
include('common_config.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
die($I['nodb']);
}
$ch=curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, USERAGENT);
curl_setopt($ch, CURLOPT_PROXY, PROXY);
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$online=$offline=$desc_online=$error=[];
$stmt=$db->prepare('SELECT address, category, md5sum, description FROM ' . PREFIX . "onions WHERE address!='' AND lasttest<(?-86400) ORDER BY lasttest LIMIT 50;");
$stmt->execute([time()]);
$onions=$stmt->fetchAll(PDO::FETCH_ASSOC);
//do tests
foreach($onions as $onion){
curl_setopt($ch, CURLOPT_URL, "http://$onion[address].onion/");
if(($site=curl_exec($ch))!==false){
// update description to title, if not yet set
if($onion['description']==='' && preg_match('~<title>([^<]+)</title>~i', $site, $match)){
$desc=preg_replace("/(\r?\n|\r\n?)/", '<br>', htmlspecialchars(html_entity_decode(trim($match[1]))));
$desc_online[]=[$desc, $onion['md5sum']];
}
$online[]=[time(), $onion['md5sum']];
// checks for server errors, to move the address to a dedicated error category
// if($onion['category']==0 && (curl_getinfo($ch, CURLINFO_HTTP_CODE)>=400 || $site==='')){
// $error[]=[$onion['md5sum']];
// }
}else{
$offline[]=[time(), $onion['md5sum'], time()];
}
}
curl_close($ch);
// update database
$online_stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET lasttest=?, lastup=lasttest, timediff=0 WHERE md5sum=?');
$offline_stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET lasttest=?, timediff=lasttest-lastup WHERE md5sum=? AND lasttest<?');
$desc_online_stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET description=? WHERE md5sum=?');
//$error_stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET category=13 WHERE md5sum=?'); //in case of error, move the address to an error category - edit the category id to fit yours!
$db->beginTransaction();
foreach($online as $tmp){
$online_stmt->execute($tmp);
}
foreach($desc_online as $tmp){
$desc_online_stmt->execute($tmp);
}
foreach($offline as $tmp){
$offline_stmt->execute($tmp);
}
//foreach($error as $tmp){
// $error_stmt->execute($tmp);
//}
$db->commit();
?>

72
common_config.php Normal file
View File

@ -0,0 +1,72 @@
<?php
/*
* Onion Link List - Configuration
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// Configuration
define('DBHOST', 'localhost'); // Database host
define('DBUSER', 'www-data'); // Database user
define('DBPASS', 'YOUR_DB_PASS'); // Database password
define('DBNAME', 'links'); // Database
define('PREFIX', ''); // Table Prefix - useful if other programs use the same names for tables - use only alpha-numeric values (A-Z, a-z, 0-9, or _)
define('PERSISTENT', true); // Use persistent database conection true/false
define('ADMINPASS', 'YOUR_ADMIN_PASS'); // Password for the admin interface
define('PROXY', '127.0.0.1:9050'); // Socks5 Proxy to connect to (Tor)
define('USERAGENT', 'Daniels Online-Test http://tt3j2x4k5ycaa5zt.onion/test.php'); // User-Agent to use when testing a site
define('LANG', 'en'); // Default language
define('PROMOTEPRICE', 0.025); // Price to promote a site for PROMOTETIME long
define('PROMOTETIME', 864000); // Time (in seconds) to promote a site payed with PROMOTEPRICE - 864000 equals 10 days
define('VERSION', '1'); // Script version
define('DBVERSION', 1); // Database layout version
//Categories - new links will always be put into the first one, leave it to Unsorted
//once configured, only add new categories at the end or you have to manually adjust the database.
$categories=['Unsorted', 'Adult/Porn', 'Communication/Social', 'Cryptocurrencies', 'Empty/Error/Unknown', 'Forums', 'Hacking', 'Hosting', 'Libraries/Wikis', 'Link Lists', 'Market/Shop/Store', 'Other', 'Personal Sites/Blogs', 'Scam', 'Security/Privacy', 'Whistleblowing'];
// Language selection
$L=array(
'de' => 'Deutsch',
'en' => 'English',
);
if(isSet($_REQUEST['lang']) && isSet($L[$_REQUEST['lang']])){
$language=$_REQUEST['lang'];
if(!isSet($_COOKIE['language']) || $_COOKIE['language']!==$language){
setcookie('language', $language);
}
}elseif(isSet($_COOKIE['language']) && isSet($L[$_COOKIE['language']])){
$language=$_COOKIE['language'];
}else{
$language=LANG;
}
include_once('lang_en.php'); //always include English
if($language!=='en'){
include_once("lang_$language.php"); //replace with translation if available
foreach($T as $name=>$translation){
$I[$name]=$translation;
}
}
function print_langs(){
global $I, $L;
echo "<small>$I[language]: ";
foreach($L as $code=>$name){
echo " <a href=\"?lang=$code\">$name</a>";
}
echo '</small>';
}
?>

97
lang_de.php Normal file
View File

@ -0,0 +1,97 @@
<?php
/*
* Onion Link List - German translation
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
$T=array(
'all' => 'Alle',
'lastadded' => 'Zuletzt hinzugefügt',
'offline' => 'Offline > 1 Woche',
'removed' => 'Entfernt',
'phishingclones'=> 'Phishingklon',
'title' => 'Onion Linkliste',
'error' => 'FEHLER',
'nodb' => 'Keine Datenbankverbindung!',
'addonion' => 'Onion-Adresse',
'adddesc' => 'Beschreibung',
'category' => 'Kategorie',
'search' => 'Suchen',
'searchterm' => 'Suchwort',
'specialcat' => 'Spezielle Kategorien',
'categories' => 'Kategorien',
'pages' => 'Seiten',
'invalonion' => 'Ungültige Onion-Adresse!',
'valid' => 'Eine gültige Adresse sieht so aus',
'succadd' => 'Onion-Adresse erfolgreich hinzugefügt!',
'faillocked' => 'Entschuldigung, das Bearbeiten dieser Onion-Adresse wurde gesperrt!',
'succupddesc' => 'Beschreibung erfolgreich aktualisiert!',
'succupdcat' => 'Kategorie erfolgreich aktualisiert!',
'alreadyknown' => 'Danke, aber ich kannte diese Adresse bereits.',
'searchresult' => 'Suche nach "%1$s", %2$d Ergebnisse gefunden:',
'link' => 'Onion Link',
'description' => 'Beschreibung',
'editdesc' => 'Beschreibung bearbeiten',
'lasttested' => 'Zuletzt getested',
'lastup' => 'Zuletzt online',
'timeadded' => 'Hinzgefügt am',
'testnow' => 'Jetzt testen',
'edit' => 'Bearbeiten',
'test' => 'Testen',
'never' => 'Nie',
'cloneof' => 'Klon von',
'admintitle' => 'Admin Schnittstelle',
'password' => 'Passwort',
'login' => 'Anmelden',
'bitcoins' => 'Bitcoins',
'remove' => 'Entfernen',
'readd' => 'Wieder hinzufügen',
'lock' => 'Sperren',
'unlock' => 'Entsperren',
'promote' => 'Hervorheben',
'unpromote' => 'Nicht mehr hervorheben',
'phishing' => 'Phishing',
'unphishing' => 'Kein Phishing',
'update' => 'Aktualisieren',
'succremove' => 'Onion-Adresse erfolgreich entfernt!',
'succreadd' => 'Onion-Adresse erfolgreich wieder hinzugefügt!',
'succlock' => 'Onion-Adresse erfolgreich gesperrt!',
'succunlock' => 'Onion-Adresse erfolgreich entsperrt!',
'succpromote' => 'Onion-Adresse erfolgreich hervorgehoben bis %1$s!',
'succunpromote' => 'Onion-Adresse erfolgreich nicht mehr hervorgehoben!',
'succaddphish' => 'Phishingklon erfolgreich hinzugefügt!',
'samephish' => 'Phishingklon nicht hinzugefügt! Phishing und original haben die gleiche Adresse.',
'succrmphish' => 'Phishingklon erfolgreich entfernt!',
'noaction' => 'Keine Aktion ausgeführt!',
'wrongpass' => 'Falsches Passwort!',
'testtitle' => 'Online-Test',
'testdesc' => 'Hier kann getestet werden, ob eine Onion-Adresse online ist oder nicht.',
'testonline' => 'Ja, der Dienst ist online!',
'testoffline' => 'Nein, der Dienst ist offline!',
'testphishing' => 'Warnung, diese Adresse ist ein bekannter Phishingklon. Die Original-Seite ist hier: %s.',
'unknown' => 'Unbekannt',
'language' => 'Sprache',
'format' => 'Format',
'pdo_mysqlextrequired' => 'Die pdo_mysql Erweiterung von PHP wird benötigt. Bitte installieren Sie diese zuerst.',
'pcreextrequired' => 'Die pcre Erweiterung von PHP wird benötigt. Bitte installieren Sie diese zuerst.',
'jsonextrequired' => 'Die json Erweiterung von PHP wird benötigt. Bitte installieren Sie diese zuerst.',
'curlextrequired' => 'Die curl Erweiterung von PHP wird benötigt. Bitte installieren Sie diese zuerst.',
'dateextrequired' => 'Die date Erweiterung von PHP wird benötigt. Bitte installieren Sie diese zuerst.',
'succdbcreate' => 'Die Datenbank wurde erfolgreich erstellt!',
'statusok' => 'Status: OK',
);
?>

97
lang_en.php Normal file
View File

@ -0,0 +1,97 @@
<?php
/*
* Onion Link List - English translation
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
$I=array(
'all' => 'All',
'lastadded' => 'Last added',
'offline' => 'Offline > 1 week',
'removed' => 'Removed',
'phishingclones'=> 'Phishing Clones',
'title' => 'Onion link list',
'error' => 'ERROR',
'nodb' => 'No database connection!',
'addonion' => 'Onion-Address',
'adddesc' => 'Description',
'category' => 'Category',
'search' => 'Search',
'searchterm' => 'Search term',
'specialcat' => 'Special categories',
'categories' => 'Categories',
'pages' => 'Pages',
'invalonion' => 'Invalid onion-Address!',
'valid' => 'A valid address looks like this',
'succadd' => 'Successfully added onion-Address!',
'faillocked' => 'Sorry, editing this onion-Address has been locked!',
'succupddesc' => 'Successfully updated description!',
'succupdcat' => 'Successfully updated category!',
'alreadyknown' => 'Thanks, but I already knew this address!',
'searchresult' => 'Searching for "%1$s", %2$d results found:',
'link' => 'Onion link',
'description' => 'Description',
'editdesc' => 'Edit description',
'lasttested' => 'Last tested',
'lastup' => 'Last seen',
'timeadded' => 'Added at',
'testnow' => 'Test now',
'edit' => 'Edit',
'test' => 'Test',
'never' => 'Never',
'cloneof' => 'Clone of',
'admintitle' => 'Admin interface',
'password' => 'Password',
'login' => 'Login',
'bitcoins' => 'Bitcoins',
'remove' => 'Remove',
'readd' => 'Re-add',
'lock' => 'Lock',
'unlock' => 'Unlock',
'promote' => 'Promote',
'unpromote' => 'Un-promote',
'phishing' => 'Phishing',
'unphishing' => 'No phishing',
'update' => 'Update',
'succremove' => 'Successfully removed onion-Address!',
'succreadd' => 'Successfully readded onion-Address!',
'succlock' => 'Successfully locked onion-Address!',
'succunlock' => 'Successfully unlocked onion-Address!',
'succpromote' => 'Successfully promoted onion-Address until %1$s!',
'succunpromote' => 'Successfully un-promoted onion-Address!',
'succaddphish' => 'Successfully added Phishing clone!',
'samephish' => 'Not added Phishing clone! Phishing and original have the same address.',
'succrmphish' => 'Successfully removed Phishing clone!',
'noaction' => 'No action taken!',
'wrongpass' => 'Wrong Pass!',
'testtitle' => 'Online-Test',
'testdesc' => 'Here an Onion-Address can be tested, for whether it is online or not.',
'testonline' => 'Yes, the service is online!',
'testoffline' => 'No, the service is offline!',
'testphishing' => 'Warning, this is a known phishing clone. The original site is located at %s.',
'unknown' => 'Unknown',
'language' => 'Language',
'format' => 'Format',
'pdo_mysqlextrequired' => 'The pdo_mysql extension of PHP is required. Please install it first.',
'pcreextrequired' => 'The pcre extension of PHP is required. Please install it first.',
'jsonextrequired' => 'The json extension of PHP is required. Please install it first.',
'curlextrequired' => 'The curl extension of PHP is required. Please install it first.',
'dateextrequired' => 'The date extension of PHP is required. Please install it first.',
'succdbcreate' => 'The database has successfully been created!',
'statusok' => 'Status: OK',
);
?>

45
lang_update.php Normal file
View File

@ -0,0 +1,45 @@
<?php
$native = 'Deutsch'; // Native lanugae name
$english = 'German'; // Enlish language name
$code = 'de'; // Language code
ob_start();
echo "<?php
/*
* Onion Link List - $english translation
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
//Native language name: $native
\$T=array(
";
if(file_exists("lang_$code.php")){
include("lang_$code.php");
}
include('lang_en.php');
foreach($T as $id=>$value){
if(isSet($I[$id])){
$I[$id]=$value;
}
}
foreach($I as $id=>$value){
echo "\t'$id' => '".str_replace("'", "\'", $value)."',\n";
}
echo ");\n?>\n";
$file=ob_get_clean();
file_put_contents("lang_$code.php", $file);
?>

393
onions.php Normal file
View File

@ -0,0 +1,393 @@
<?php
/*
* Onion Link List - Main listing script
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
if($_SERVER['REQUEST_METHOD']==='HEAD'){
exit; // ignore headers, no further processing needed
}
include('common_config.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
}
date_default_timezone_set('UTC');
//select output format
if(!isset($_REQUEST['format'])){
send_html();
}elseif($_REQUEST['format']==='text'){
send_text();
}elseif($_REQUEST['format']==='json'){
send_json();
}else{
send_html();
}
function send_html(){
global $I, $categories, $db, $language;
header('Content-Type: text/html; charset=UTF-8');
asort($categories);
//sql for special categories
$special=[
$I['all']=>"address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND timediff<604800',
$I['lastadded']=>"address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing)',
$I['offline']=>"address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND timediff>604800'
];
if(!isSet($_REQUEST['pg'])){
$_REQUEST['pg']=1;
}else{
settype($_REQUEST['pg'], 'int');
}
if($_REQUEST['pg']>0){
$_REQUEST['newpg']=1;
}else{
$_REQUEST['newpg']=0;
}
echo '<!DOCTYPE html><html><head>';
echo "<title>$I[title]</title>";
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<style type="text/css">.red{color:red;} .green{color:green;} .up{background-color:#008000;} .down{background-color:#FF0000;} .promo{outline:medium solid #FFD700;} .list{display: inline-block; padding: 0px; margin: 0px;} .list li{display:inline;} .active{font-weight:bold;}</style>';
echo '</head><body>';
echo "<h2>$I[title]</h2>";
print_langs();
echo "<br><small>$I[format]: <a href=\"?format=text\">Text</a> <a href=\"?format=json\">JSON</a></small>";
if(!isSet($db)){
echo "<p><b class=\"red\">$I[error]:</b> $I[nodb]</p>";
echo '</body></html>';
exit;
}
echo '<p>I\'m not responsible for any content of websites linked here. Be careful and use your brain.</p><p>Do you want your address to be highlighted and featured at the top of the results? Send Bitcoins to <a href="bitcoin:1CHvjeMJum2Zfd3JEdb35RUEdz1jjQvdPT">1CHvjeMJum2Zfd3JEdb35RUEdz1jjQvdPT</a> and then <a href="/contact.php">tell me</a> your transaction ID and which address(es) you want to be highlighted. 0.025 BTC equals 10 days for one address. Any other amount can be calculated thereof.</p>';
//update onions description form
echo "<table><tr valign=\"top\"><td><form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\">";
echo "<input type=\"hidden\" name=\"pg\" value=\"$_REQUEST[newpg]\">";
echo "<input type=\"hidden\" name=\"lang\" value=\"$language\">";
echo "<p>$I[addonion]: <br><input name=\"addr\" size=\"30\" placeholder=\"http://$_SERVER[HTTP_HOST]\" value=\"";
if(isSet($_REQUEST['addr'])){
echo htmlspecialchars($_REQUEST['addr']);
}
echo '" required></p>';
echo "<p>$I[adddesc]: <br><textarea name=\"desc\" rows=\"2\" cols=\"30\">";
if(!empty($_REQUEST['desc'])){//use posted description
echo htmlspecialchars(trim($_REQUEST['desc']));
}elseif(!empty($_REQUEST['addr'])){//fetch description from database
if(preg_match('~(^(https?://)?([a-z0-9]*\.)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', trim($_REQUEST['addr']), $addr)){
$addr=strtolower($addr[4]);
$md5=md5($addr, true);
$stmt=$db->prepare('SELECT description, category FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute(array($md5));
if($desc=$stmt->fetch(PDO::FETCH_ASSOC)){
$category=$desc['category'];
echo str_replace('<br>', "\n", $desc['description']);
}
}
}
echo '</textarea></p>';
if(isSet($_REQUEST['cat']) && $_REQUEST['cat']<(count($categories)+count($special)+1) && $_REQUEST['cat']>=0){
settype($_REQUEST['cat'], 'int');
$category=$_REQUEST['cat'];
}
if(!isSet($category)){
$category=count($categories);
}
echo "<p>$I[category]: <select name=\"cat\">";
foreach($categories as $cat=>$name){
echo "<option value=\"$cat\"";
if($category==$cat || ($cat===0 && $category>=count($categories))){
echo ' selected';
}
echo ">$name</option>";
}
echo '</select></p>';
echo "<input type=\"submit\" name=\"action\" value=\"$I[update]\"></form></td>";
//search from
echo "<td><form action=\"$_SERVER[SCRIPT_NAME]\" method=\"post\">";
echo "<input type=\"hidden\" name=\"pg\" value=\"$_REQUEST[newpg]\">";
echo "<input type=\"hidden\" name=\"lang\" value=\"$language\">";
echo "<p>$I[search]: <br><input name=\"q\" size=\"30\" placeholder=\"$I[searchterm]\" value=\"";
if(isSet($_REQUEST['q'])){
echo htmlspecialchars($_REQUEST['q']);
}
echo '" required></p>';
echo "<input type=\"submit\" name=\"action\" value=\"$I[search]\"></form></td>";
echo '</tr></table><br>';
//List special categories
echo "<ul class=\"list\"><li>$I[specialcat]:</li>";
$cat=count($categories);
$pages=1;
foreach($special as $name=>$query){
if($cat===count($categories)+1){
$num[0]=100;
}else{
$num=$db->query('SELECT COUNT(*) FROM ' . PREFIX . "onions WHERE $query;")->fetch(PDO::FETCH_NUM);
}
if($category==$cat){
echo " <li class=\"active\"><a href=\"?cat=$cat&amp;pg=$_REQUEST[newpg]&amp;lang=$language\">$name ($num[0])</a></li>";
$pages=ceil($num[0]/100);
}else{
echo " <li><a href=\"?cat=$cat&amp;pg=$_REQUEST[newpg]&amp;lang=$language\">$name ($num[0])</a></li>";
}
++$cat;
}
$num=$db->query('SELECT COUNT(*) FROM ' . PREFIX . 'phishing, ' . PREFIX . 'onions WHERE ' . PREFIX . "onions.id=onion_id AND address!='';")->fetch(PDO::FETCH_NUM);
if($category==$cat){
echo " <li class=\"active\"><a href=\"?cat=$cat&amp;lang=$language\">$I[phishingclones] ($num[0])</a></li>";
}else{
echo " <li><a href=\"?cat=$cat&amp;lang=$language\">$I[phishingclones] ($num[0])</a></li>";
}
$num=$db->query('SELECT COUNT(*) FROM ' . PREFIX . "onions WHERE address='';")->fetch(PDO::FETCH_NUM);
echo " <li>$I[removed] ($num[0])</li></ul><br><br>";
//List normal categories
echo "<ul class=\"list\"><li>$I[categories]:</li>";
$stmt=$db->prepare('SELECT COUNT(*) FROM ' . PREFIX . "onions WHERE category=? AND address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing);');
foreach($categories as $cat=>$name){
$stmt->execute(array($cat));
$num=$stmt->fetch(PDO::FETCH_NUM);
if($category==$cat){
echo " <li class=\"active\"><a href=\"?cat=$cat&amp;pg=$_REQUEST[newpg]&amp;lang=$language\">$name ($num[0])</a></li>";
$pages=ceil($num[0]/100);
}else{
echo " <li><a href=\"?cat=$cat&amp;pg=$_REQUEST[newpg]&amp;lang=$language\">$name ($num[0])</a></li>";
}
}
echo '</ul><br><br>';
if($_SERVER['REQUEST_METHOD']==='POST' && !empty($_REQUEST['addr'])){
if(!preg_match('~(^(https?://)?([a-z0-9]*\.)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', trim($_REQUEST['addr']), $addr)){
echo "<p class=\"red\">$I[invalonion]</p>";
echo "<p>$I[valid]: http://tt3j2x4k5ycaa5zt.onion</p>";
}else{
$addr=strtolower($addr[4]);
$md5=md5($addr, true);
$stmt=$db->prepare('SELECT locked FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute(array($md5));
$stmt->bindColumn(1, $locked);
if($category==count($categories)){
$category=0;
}
if(!isSet($_POST['desc'])){
$desc='';
}else{
$desc=trim($_POST['desc']);
$desc=htmlspecialchars($desc);
$desc=preg_replace("/(\r?\n|\r\n?)/", '<br>', $desc);
}
if(!$stmt->fetch(PDO::FETCH_BOUND)){//new link, add to database
$stmt=$db->prepare('INSERT INTO ' . PREFIX . 'onions (address, description, md5sum, category) VALUES (?, ?, ?, ?);');
$stmt->execute(array($addr, $desc, $md5, $category));
echo "<p class=\"green\">$I[succadd]</p>";
}elseif($locked==1){//locked, not editable
echo "<p class=\"red\">$I[faillocked]</p>";
}elseif($desc!==''){//update description
$stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET description=?, category=? WHERE md5sum=?;');
$stmt->execute(array($desc, $category, $md5));
echo "<p class=\"green\">$I[succupddesc]</p>";
}elseif($category!=0){//update category only
$stmt=$db->prepare('UPDATE ' . PREFIX . 'onions SET category=? WHERE md5sum=?;');
$stmt->execute(array($category, $md5));
echo "<p class=\"green\">$I[succupdcat]</p>";
}else{//nothing changed and already known
echo "<p class=\"green\">$I[alreadyknown]</p>";
}
}
}
if($pages>1 && empty($_REQUEST['q'])){
$pagination=get_pagination($category, $pages);
echo $pagination;
}else{
$pagination='';
}
if(!empty($_REQUEST['q'])){//run search query
$stmt=$db->prepare('SELECT address, lasttest, lastup, timeadded, description, locked, special FROM ' . PREFIX . "onions WHERE address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND (description LIKE ? OR address LIKE ?) ORDER BY address;');
$query=htmlspecialchars($_REQUEST['q']);
$query="%$query%";
$stmt->execute(array($query, $query));
$table=get_table($stmt, $numrows);
printf("<p><b>$I[searchresult]</b></p>", $_REQUEST['q'], $numrows);
echo $table;
}elseif($category>=count($categories)+count($special)){//show phishing clones
print_phishing_table();
}elseif($category>=count($categories)){//show special categories
$tmp=$category-count($categories);
foreach($special as $name=>$query){
if($tmp===0) break;
--$tmp;
}
if($category-count($categories)===1){
$query.=' ORDER BY id DESC LIMIT 100';
}else{
$query.=' ORDER BY address';
if($_REQUEST['pg']>0){
$offset=100*($_REQUEST['pg']-1);
$query.=" LIMIT 100 OFFSET $offset";
}
}
$stmt=$db->query('SELECT address, lasttest, lastup, timeadded, description, locked, special FROM ' . PREFIX . "onions WHERE $query;");
echo get_table($stmt, $numrows, true);
}else{//show normal categories
if($_REQUEST['pg']>0){
$offset=100*($_REQUEST['pg']-1);
$offsetquery=" LIMIT 100 OFFSET $offset";
}else{
$offsetquery='';
}
$stmt=$db->prepare('SELECT address, lasttest, lastup, timeadded, description, locked, special FROM ' . PREFIX . "onions WHERE address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . "phishing) AND category=? AND timediff<604800 ORDER BY address$offsetquery;");
$stmt->execute(array($category));
echo get_table($stmt, $numrows, true);
}
echo '<br>';
echo $pagination;
echo '<br><p style="text-align:center;font-size:small;"><a target="_blank" href="https://github.com/DanWin/onion-link-list">Onion Link List - ' . VERSION . '</a></p>';
echo '</body></html>';
}
function get_table($stmt, &$numrows=0, $promoted=false){
global $I, $db, $language;
$time=time();
ob_start();
echo "<table border=\"1\"><tr><th>$I[link]</th><th>$I[description]</th><th>$I[editdesc]</th><th>$I[lasttested]</th><th>$I[lastup]</th><th>$I[timeadded]</th><th>$I[testnow]</th></tr>";
if($promoted){//print promoted links at the top
$time=time();
$promo=$db->prepare('SELECT address, lasttest, lastup, timeadded, description, locked, special FROM ' . PREFIX . "onions WHERE special>? AND address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND timediff<604800 ORDER BY address;');
$promo->execute(array($time));
while($link=$promo->fetch(PDO::FETCH_ASSOC)){
if($link['lastup']===$link['lasttest']){
$class='up';
}else{
$class='down';
}
if($link['lastup']==0){
$lastup=$I['never'];
}else{
$lastup=date('Y-m-d H:i:s', $link['lastup']);
}
if($link['lasttest']==0){
$lasttest=$I['never'];
}else{
$lasttest=date('Y-m-d H:i:s', $link['lasttest']);
}
$timeadded=date('Y-m-d H:i:s', $link['timeadded']);
echo "<tr class=\"$class promo\"><td><a href=\"http://$link[address].onion\" target=\"_blank\">$link[address].onion</a></td><td>$link[description]</td><td>-</td><td>$lasttest</td><td>$lastup</td><td>$timeadded</td><td><form target=\"_blank\" method=\"post\" action=\"test.php\"><input name=\"addr\" value=\"$link[address]\" type=\"hidden\"><input name=\"lang\" value=\"$language\" type=\"hidden\"><input value=\"$I[test]\" type=\"submit\"></form></td></tr>";
}
}
while($link=$stmt->fetch(PDO::FETCH_ASSOC)){
if($link['lastup']===$link['lasttest']){
$class='up';
}else{
$class='down';
}
if($link['lastup']==0){
$lastup=$I['never'];
}else{
$lastup=date('Y-m-d H:i:s', $link['lastup']);
}
if($link['lasttest']==0){
$lasttest=$I['never'];
$class='';
}else{
$lasttest=date('Y-m-d H:i:s', $link['lasttest']);
}
$timeadded=date('Y-m-d H:i:s', $link['timeadded']);
if($link['special']>$time){
$class.=' promo';
}
if($link['locked']==1){
$edit='-';
}else{
$edit="<form target=\"_blank\"><input name=\"addr\" value=\"$link[address]\" type=\"hidden\"><input type=\"hidden\" name=\"pg\" value=\"$_REQUEST[newpg]\"><input type=\"hidden\" name=\"lang\" value=\"$language\"><input value=\"$I[edit]\" type=\"submit\"></form>";
}
echo "<tr class=\"$class\"><td><a href=\"http://$link[address].onion\" target=\"_blank\">$link[address].onion</a></td><td>$link[description]</td><td>$edit</td><td>$lasttest</td><td>$lastup</td><td>$timeadded</td><td><form target=\"_blank\" method=\"post\" action=\"test.php\"><input name=\"addr\" value=\"$link[address]\" type=\"hidden\"><input type=\"hidden\" name=\"lang\" value=\"$language\"><input value=\"$I[test]\" type=\"submit\"></form></td></tr>";
++$numrows;
}
echo '</table>';
return ob_get_clean();
}
function print_phishing_table(){
global $I, $db;
echo "<table border=\"1\"><tr><th>$I[link]</th><th>$I[cloneof]</th><th>$I[lastup]</th></tr>";
$stmt=$db->query('SELECT address, original, lasttest, lastup FROM ' . PREFIX . 'onions, ' . PREFIX . 'phishing WHERE ' . PREFIX . "onions.id=onion_id AND address!='' ORDER BY onions.address;");
while($link=$stmt->fetch(PDO::FETCH_ASSOC)){
if($link['lastup']===$link['lasttest']){
$class='up';
}else{
$class='down';
}
if($link['lastup']==0){
$lastup=$I['never'];
}else{
$lastup=date('Y-m-d H:i:s', $link['lastup']);
}
if($link['original']!==''){
$orig="<a href=\"http://$link[original].onion\" target=\"_blank\">$link[original].onion</a>";
}else{
$orig=$I['unknown'];
}
echo "<tr class=\"$class\"><td>$link[address].onion</td><td>$orig</td><td>$lastup</td></tr>";
}
echo '</table>';
}
function send_text(){
global $db;
if(!isSet($db)){
die("$I[error]: $I[nodb]");
}
header('Content-Type: text/plain; charset=UTF-8');
$stmt=$db->query('SELECT address FROM ' . PREFIX . "onions WHERE address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND timediff<604800 ORDER BY address;');
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
echo "$tmp[0].onion\n";
}
}
function send_json(){
global $db, $categories;
if(!isSet($db)){
die("$I[error]: $I[nodb]");
}
header('Content-Type: application/json;');
$data=['categories'=>$categories];
$stmt=$db->query('SELECT address, category, description, locked, lastup, lasttest, timeadded FROM ' . PREFIX . "onions WHERE address!='' AND id NOT IN (SELECT onion_id FROM " . PREFIX . 'phishing) AND timediff<604800 ORDER BY address;');
$data['onions']=$stmt->fetchALL(PDO::FETCH_ASSOC);
$stmt=$db->query('SELECT md5sum FROM ' . PREFIX . "onions WHERE address='';");
while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
$data['removed'][]=bin2hex($tmp['md5sum']);
}
$stmt=$db->query('SELECT address, original FROM ' . PREFIX . 'onions, ' . PREFIX . 'phishing WHERE onion_id=' . PREFIX . "onions.id AND address!='' AND timediff<604800 ORDER BY address;");
$data['phishing']=$stmt->fetchALL(PDO::FETCH_ASSOC);
echo json_encode($data);
}
function get_pagination($category, $pages){
global $I, $language;
ob_start();
echo "<ul class=\"list\"><li>$I[pages]:</li>";
if($_REQUEST['pg']==0){
echo " <li class=\"active\"><a href=\"?cat=$category&amp;pg=0&amp;lang=$language\">$I[all]</a></li>";
}else{
echo " <li><a href=\"?cat=$category&amp;pg=0&amp;lang=$language\">$I[all]</a></li>";
}
for($i=1; $i<=$pages; ++$i){
if($_REQUEST['pg']==$i){
echo " <li class=\"active\"><a href=\"?cat=$category&amp;pg=$i&amp;lang=$language\">$i</a></li>";
}else{
echo " <li><a href=\"?cat=$category&amp;pg=$i&amp;lang=$language\">$i</a></li>";
}
}
echo "</ul><br><br>";
return ob_get_clean();
}
?>

68
phishing_tests.php Normal file
View File

@ -0,0 +1,68 @@
<?php
/*
* Onion Link List - Automated test for phishing clones
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// Executed every 25 hours via cron - checks for phishing clones on known phishing sites.
date_default_timezone_set('UTC');
include('common_config.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
die($I['nodb']);
}
$ch=curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, PROXY);
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 25);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
check('http://tt3j2x4k5ycaa5zt.onion/onions.php?cat=15&pg=0', 'http://tt3j277rncfaqmj7.onion/onions.php?cat=15&pg=0');
check('http://skunksworkedp2cg.onion/sites.html', 'http://skunkrdunsylcfqd.onion/sites.html');
function check($link, $phishing_link){
global $ch, $db;
curl_setopt($ch, CURLOPT_URL, $link);
$links=curl_exec($ch);
curl_setopt($ch, CURLOPT_URL, $phishing_link);
$phishing_links=curl_exec($ch);
if(!empty($links) && !empty($phishing_links)){
$phishings=$db->prepare('INSERT IGNORE INTO ' . PREFIX . 'phishing (onion_id, original) VALUES ((SELECT id FROM onions WHERE md5sum=?), ?);');
$select=$db->prepare('SELECT id FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$insert=$db->prepare('INSERT INTO ' . PREFIX . 'onions (address, md5sum, timeadded) VALUES (?, ?, ?);');
preg_match_all('~(https?://)?([a-z0-9]*\.)?([a-z2-7]{16}).onion(/[^\s><"]*)?~i', $links, $addr);
preg_match_all('~(https?://)?([a-z0-9]*\.)?([a-z2-7]{16}).onion(/[^\s><"]*)?~i', $phishing_links, $phishing_addr);
$count=count($addr[3]);
if($count===count($phishing_addr[3])){ //only run with same data set
for($i=0; $i<$count; ++$i){
if($addr[3][$i]!==$phishing_addr[3][$i]){
$address=strtolower($addr[3][$i]);
$phishing_address=strtolower($phishing_addr[3][$i]);
$md5=md5($phishing_address, true);
$select->execute([$md5]);
if(!$select->fetch(PDO::FETCH_NUM)){
$insert->execute([$phishing_address, $md5, time()]);
}
$phishings->execute([$md5, $address]);
}
}
}
}
}
?>

62
setup.php Normal file
View File

@ -0,0 +1,62 @@
<?php
/*
* Onion Link List - Setup
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
include('common_config.php');
if(!extension_loaded('pdo_mysql')){
die($I['pdo_mysqlextrequired']);
}
if(!extension_loaded('pcre')){
die($I['pcreextrequired']);
}
if(!extension_loaded('json')){
die($I['jsonextrequired']);
}
if(!extension_loaded('json')){
die($I['curlextrequired']);
}
if(!extension_loaded('date')){
die($I['dateextrequired']);
}
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
try{
//Attempt to create database
$db=new PDO('mysql:host=' . DBHOST, DBUSER, DBPASS, $options);
if(false!==$db->exec('CREATE DATABASE ' . DBNAME)){
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}else{
die($I['nodb']);
}
}catch(PDOException $e){
die($I['nodb']);
}
}
if(!@$db->query('SELECT * FROM ' . PREFIX . 'settings LIMIT 1;')){
//create tables
$db->exec('CREATE TABLE ' . PREFIX . 'onions (id int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, address varchar(16) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, md5sum binary(16) NOT NULL UNIQUE, lasttest int(10) UNSIGNED NOT NULL, lastup int(10) UNSIGNED NOT NULL, timediff int(10) UNSIGNED NOT NULL, timeadded int(10) UNSIGNED NOT NULL, description varchar(20000) CHARACTER SET utf8 NOT NULL, category smallint(6) NOT NULL, locked smallint(6) NOT NULL, special int(10) UNSIGNED NOT NULL, INDEX(address), INDEX(lasttest), INDEX(timediff), INDEX(category), INDEX(special));');
$db->exec('CREATE TABLE ' . PREFIX . 'phishing (id int(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, onion_id int(10) UNSIGNED NOT NULL UNIQUE, original varchar(16) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, FOREIGN KEY (onion_id) REFERENCES onions(id) ON DELETE CASCADE ON UPDATE CASCADE);');
$db->exec('CREATE TABLE ' . PREFIX . 'settings (setting varchar(50) NOT NULL PRIMARY KEY, value varchar(20000) NOT NULL);');
$db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('version', '1');");
echo "$I[succdbcreate]\n";
}else{
echo "$I[statusok]\n";
}
?>

95
test.php Normal file
View File

@ -0,0 +1,95 @@
<?php
/*
* Onion Link List - Manual testing of hidden services
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
header('Content-Type: text/html; charset=UTF-8');
if($_SERVER['REQUEST_METHOD']==='HEAD'){
exit; // headers sent, no further processing needed
}
include('common_config.php');
echo '<!DOCTYPE html><html><head>';
echo "<title>Daniel - $I[testtitle]</title>";
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<style type="text/css">.red{color:red;} .green{color:green;}</style>';
echo '</head><body>';
echo '<h2>Online-Test</h2>';
print_langs();
echo "<p>$I[testdesc]</p>";
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\">";
echo "<input type=\"hidden\" name=\"lang\" value=\"$language\">";
echo "<p>$I[link]: <br><input name=\"addr\" size=\"30\" value=\"";
if(isSet($_REQUEST['addr'])){
echo htmlspecialchars($_REQUEST['addr']);
}else{
echo "http://$_SERVER[HTTP_HOST]";
}
echo '" required></p>';
echo "<input type=\"submit\" name=\"action\" value=\"$I[test]\"></form><br>";
if(!empty($_REQUEST['addr'])){
if(ob_get_level()>0){
ob_end_flush();
}
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
}
if(!preg_match('~(^(https?://)?([a-z0-9]*\.)?([a-z2-7]{16})(\.onion(/.*)?)?$)~i', trim($_REQUEST['addr']), $addr)){
echo "<p class=\"red\">$I[invalonion]</p>";
echo "<p>$I[valid]: http://tt3j2x4k5ycaa5zt.onion</p>";
}else{
$ch=curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, USERAGENT);
curl_setopt($ch, CURLOPT_PROXY, PROXY);
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_URL, "http://$addr[4].onion/");
$addr=strtolower($addr[4]);
$md5=md5($addr, true);
//display warning, if a phishing clone was tested
$phishing=$db->prepare('SELECT original FROM ' . PREFIX . 'phishing, ' . PREFIX . 'onions WHERE address=? AND onion_id=' . PREFIX . 'onions.id;');
$phishing->execute(array($addr));
if($orig=$phishing->fetch(PDO::FETCH_NUM)){
printf("<p class=\"red\">$I[testphishing]</p>", "<a href=\"http://$orig[0].onion\">$orig[0].onion</a>");
}
if(curl_exec($ch)!==false){
if(isSet($db)){
//update entry in database
$stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'onions WHERE md5sum=?;');
$stmt->execute(array($md5));
if(!$stmt->fetch(PDO::FETCH_NUM)){
$db->prepare('INSERT INTO ' . PREFIX . 'onions (address, md5sum, timeadded) VALUES (?, ?, ?);')->execute(array($addr, $md5, time()));
}
$db->prepare('UPDATE ' . PREFIX . 'onions SET lasttest=?, lastup=lasttest, timediff=0 WHERE md5sum=?;')->execute(array(time(), $md5));
}
echo "<p class=\"green\">$I[testonline]</p>";
}else{
if(isSet($db)){
$time=time();
$db->prepare('UPDATE ' . PREFIX . 'onions SET lasttest=?, timediff=lasttest-lastup WHERE md5sum=? AND lasttest<?;')->execute(array($time, $md5, $time));
}
echo "<p class=\"red\">$I[testoffline]</p>";
}
curl_close($ch);
}
}
echo '<br><p style="text-align:center;font-size:small;"><a target="_blank" href="https://github.com/DanWin/onion-link-list">Onion Link List - ' . VERSION . '</a></p>';
echo '</body></html>';
?>

75
update.php Normal file
View File

@ -0,0 +1,75 @@
<?php
/*
* Onion Link List - Automated import of new onion sites
*
* Copyright (C) 2016 Daniel Winzen <d@winzen4.de>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
// Executed every 24 hours via cron - checks for new sites.
include('common_config.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
die($I['nodb']);
}
$ch=curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, PROXY);
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 25);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$onions=[];
//sources to get links from
check_links($onions, $ch, 'https://tt3j2x4k5ycaa5zt.onion.to/antanistaticmap/stats/yesterday');
check_links($onions, $ch, 'https://tt3j2x4k5ycaa5zt.tor2web.org/antanistaticmap/stats/yesterday');
check_links($onions, $ch, 'http://tt3j2x4k5ycaa5zt.onion/onions.php?format=text');
check_links($onions, $ch, 'http://skunksworkedp2cg.onion/sites.txt');
check_links($onions, $ch, 'http://7cbqhjnlkivmigxf.onion/');
check_links($onions, $ch, 'http://visitorfi5kl7q7i.onion/address/');
//add them to the database
add_onions($onions, $db);
//delete links that were not seen within a month
$db->exec('DELETE FROM ' . PREFIX . "onions WHERE address!='' AND timediff>2419200 AND lasttest-timeadded>2419200;");
function check_links(&$onions, &$ch, $link){
curl_setopt($ch, CURLOPT_URL, $link);
$links=curl_exec($ch);
if(preg_match_all('~(https?://)?([a-z0-9]*\.)?([a-z2-7]{16}).onion(/[^\s><"]*)?~i', $links, $addr)){
foreach($addr[3] as $link){
$link=strtolower($link);
$onions[md5($link, true)]=$link;
}
}
}
function add_onions(&$onions, $db){
$stmt=$db->query('SELECT md5sum FROM ' . PREFIX . 'onions;');
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
if(isSet($onions[$tmp[0]])){
unset($onions[$tmp[0]]);
}
}
$time=time();
$insert=$db->prepare('INSERT INTO ' . PREFIX . 'onions (address, md5sum, timeadded) VALUES (?, ?, ?);');
$db->beginTransaction();
foreach($onions as $md5=>$addr){
$insert->execute([$addr, $md5, $time]);
}
$db->commit();
}
?>