mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 17:28:55 +00:00
530 lines
17 KiB
PHP
530 lines
17 KiB
PHP
<?php
|
|
// Author l2g
|
|
// Date: Mar 17th, 2013
|
|
// Version: 0.97.4
|
|
//
|
|
// Description:
|
|
// This script is an implementation of spotnet and newznab to which
|
|
// multiple servers can share comments and information amongst each other
|
|
//
|
|
// The implementation is based loosely on how spotweb works. If you don't know
|
|
// what spotweb is, feel free to Google it.
|
|
//
|
|
// With an spotnab, you have 2 options:
|
|
// 1. Fetch comments (and potential other things as we dream them up) from
|
|
// other newznab sources and apply them to your own comment section.
|
|
//
|
|
// Fetched content is scanned and decrypted using a password that the
|
|
// newznab server who posted it chooses to share with you. If you can't
|
|
// decrypt the post then you move along. Since all newznab servers choose
|
|
// to share and or not to share. Spotnab will only populate your database
|
|
// with comments from the sources who choose to share their comments
|
|
// with you.
|
|
//
|
|
// A few public keys will be configured out of the box so that you can
|
|
// retrieve your comments from existing active sites should you choose
|
|
// to enable them.
|
|
//
|
|
// 2. Post comments; send all the comments made by your local users of your
|
|
// site to usenet encrypted by your own secure private key. Only those you
|
|
// share your public key will be allowed to decrypt it for their own
|
|
// server.
|
|
//
|
|
// Releases are uniquely bundled and shared across NewzNab servers through the
|
|
// use of the releases table. To uniquely identify a release across remote
|
|
// servers we need to extract the Message-ID from the first segment of the first
|
|
// file of the matched release (as it was posted to usenet). This ID is unique
|
|
// to usenet, so it'll be unique to us as well. We can achive this information
|
|
// from parsing the NZB file generated by the NewzNab server.
|
|
//
|
|
// This value can be certain to not conflict and uniquely identify a release
|
|
// across all NewzNab Servers.
|
|
//
|
|
// Content is posted and retrieved to Usnet in JSON encrypted using the key
|
|
// belonging to the NewzNab Server.
|
|
//
|
|
// Structure is as follows:
|
|
// {
|
|
// server: {
|
|
// code: <string>,
|
|
// title: <string>,
|
|
// },
|
|
// postdate_utc: 'YYYY-MM-DD hh:mm:ss.ms',
|
|
// comments: [
|
|
// {
|
|
// gid: <char[32]>,
|
|
// cid: <char[32]>,
|
|
// comment: <string>,
|
|
// is_visible: <bool>,
|
|
// username: <string>,
|
|
// postdate_utc: 'YYYY-MM-DD hh:mm:ss',
|
|
// }
|
|
// ]
|
|
// }
|
|
//
|
|
// server: Meta information on the server that posted the spot.
|
|
//
|
|
// server
|
|
// -/ code: This is taken from the users local database `site` table. It is
|
|
// the `code` the user configured their newznab server as.
|
|
//
|
|
// -/ title: This is also taken from the users local database `site` table. It
|
|
// is the the `title` the user configured their newznab server as.
|
|
//
|
|
// postdate_utc: This is the current time measured in the number of seconds since
|
|
// the Unix Epoch (January 1 1970 00:00:00 GMT). This represents
|
|
// the local UTC time of when this message was posted. It doesn't
|
|
// reflect the age of the content to follow.
|
|
//
|
|
// comments: This is an array of comment objects
|
|
//
|
|
// comments
|
|
// -/ gid: This is the Global Identifier for the release the comment
|
|
// is in relation to.
|
|
//
|
|
// -/ cid: This is a unique global identifier used to identify the comment
|
|
// itself. This allows the server to publish the comment again
|
|
// if there is an update to it's data (such as toggling it to a
|
|
// hidden type). This should be used to prevent a duplicate
|
|
// entry in the comments table when dealing with remote content.
|
|
//
|
|
// -/ comment: This is the actual comment itself associated with the release
|
|
//
|
|
// -/ is_visible: Whether or not the comment should be marked visible or not.
|
|
//
|
|
// -/ username: The username of the person who made the comment.
|
|
//
|
|
// -/ postdate_utc: The timestamp (in UTC) that the comment was created at.
|
|
//
|
|
|
|
/*
|
|
|
|
INSTRUCTIONS
|
|
============
|
|
|
|
Both posting and fetching will 'NOT' work unless you've generated
|
|
Global Release ID values for all of your current releases... this is
|
|
done by running the command:
|
|
|
|
#> php spotnab.php -g
|
|
|
|
POSTING
|
|
1. To run all of the SQL statements identifed above
|
|
|
|
2. You 'must' have all Global Release ID's defined for each
|
|
release or the comments associated with it will not be
|
|
included in the post.
|
|
|
|
3. Generate yourself your own set of SSL keys:
|
|
#> php spotnab.php -k
|
|
|
|
4. At this point your ready to post... If you run the following SQL
|
|
statement, you'll mark all your existing comments:
|
|
|
|
-- Ensure spotnab posting is enabled:
|
|
UPDATE `site` set `value` = '1' WHERE `setting` = 'spotnabpost';
|
|
|
|
-- Posting actually uses this date as a reference to when
|
|
-- it last posted. So set it to a date so far back in time
|
|
-- that all your existing comments become declared as unposted.
|
|
|
|
UPDATE `site` set `updateddate` = '1980-01-01 00:00:00'
|
|
WHERE `setting` = 'spotnabpost' AND `value` = '1';
|
|
|
|
FETCHING
|
|
1. You need to acquire and enable sources. A source is as simple
|
|
as someone providing you their public key they generated using
|
|
the --keygen (-k) switch.
|
|
|
|
2. Fetch releases:
|
|
#> php spotnab.php -f
|
|
|
|
3. Consider fetching your own posts back just to test things out...:
|
|
|
|
SET @key := (SELECT value FROM settings WHERE setting = 'spotnabsitepubkey');
|
|
INSERT INTO `spotnabsources` (`ID` , `username`, `useremail` ,
|
|
`usenetgroup`, `publickey` , `active` ,
|
|
`description` , `lastupdate` )
|
|
VALUES ( NULL , 'nntp', 'spot@nntp.com', 'alt.binaries.backup', @key,
|
|
'1', '1', 'My Key Fetch Test', NULL);
|
|
|
|
Then you can run the fetch release command again to poll for
|
|
stuff you posted already (if you did).
|
|
|
|
#> php spotnab.php -f
|
|
|
|
SHARING
|
|
1. Use the -k switch on the tool to retrieve your public key...
|
|
share it... let people use the comments posted on your site
|
|
get them to do the same to you. Eliminating crappy content
|
|
couldn't be more easy.
|
|
|
|
Spotnab now has a built in feature to post a discovery message
|
|
for others to grab automatically. Just call:
|
|
#> php spotnab.php -b
|
|
|
|
You can also fetch messages from those who have already
|
|
posted their own discovery message by calling:
|
|
#> php spotnab.php -d
|
|
|
|
Just note that anything auto-discovered is disabled by default
|
|
so you need to go into your options and 'enable' it if you
|
|
recognize or want to test out the source.
|
|
*/
|
|
|
|
require_once dirname(__FILE__) . '/../../www/config.php';
|
|
|
|
// Subject Lines will always be a hash key that helps scanning identify whether
|
|
// or not the contents are valid or not. the hash key contains is built
|
|
// by applying the password key against the md5 some of the message content
|
|
// itself. Unmatched content is ignored.
|
|
|
|
$shortopts = "";
|
|
$shortopts .= "G";
|
|
$shortopts .= "g";
|
|
$shortopts .= "r";
|
|
$shortopts .= "p";
|
|
$shortopts .= "f";
|
|
$shortopts .= "t";
|
|
$shortopts .= "k";
|
|
$shortopts .= "o";
|
|
$shortopts .= "K";
|
|
$shortopts .= "d";
|
|
$shortopts .= "b";
|
|
$shortopts .= "F::";
|
|
|
|
$longopts = array(
|
|
"post",
|
|
"fetch",
|
|
"fetch-backfill::",
|
|
"discover",
|
|
"broadcast",
|
|
"test",
|
|
"populate-gid",
|
|
"populate-fix-gid",
|
|
"soft-reset",
|
|
"keygen",
|
|
"force-keygen",
|
|
"clean-orphan-comments"
|
|
);
|
|
|
|
$options = getopt($shortopts, $longopts);
|
|
|
|
function display_help(){
|
|
echo "\n";
|
|
echo "SpotNab v0.97.4, Author: l2g\n";
|
|
echo "Syntax: spotnab.php <action>\n";
|
|
echo "\n";
|
|
echo "Actions:\n";
|
|
echo " -g, --populate-gid This could be considered phase one of "
|
|
."this project.\n";
|
|
echo " requiring that your releases database"
|
|
." table is up to date\n";
|
|
echo " with all GID (Global Identifiers) so"
|
|
." it can correctly\n";
|
|
echo " communicate with other servers that "
|
|
."share the same content\n";
|
|
echo " from the servers configured.\n";
|
|
echo " -G, --populate-fix-gid Same as -g except broken nzb files are "
|
|
."also broken releases.\n";
|
|
echo " Specifying this switch will remove "
|
|
."these dead releses.\n";
|
|
echo " -f, --fetch Get latest spotnab comments from "
|
|
."usenet using the information\n";
|
|
echo "\n";
|
|
echo " -F=DAYS\n";
|
|
echo " --fetch-backfill=DAYS Get latest spotnab comments as far back"
|
|
." as the days specified.\n";
|
|
echo "\n";
|
|
echo " -p, --post Post latest updates from local system "
|
|
."to usenet.\n";
|
|
echo "\n";
|
|
echo " -k, --keygen Generate a new SSL Public/Private Key "
|
|
."pair only if one isn't\n";
|
|
echo " already generated.\n";
|
|
echo " -K, --force-keygen Generate a new SSL Public/Private Key "
|
|
."pair\n";
|
|
echo "\n";
|
|
echo " -d, --discover Attempt to discovery all sources available.\n";
|
|
echo "\n";
|
|
echo " -o, --clean-orphan-comments\n";
|
|
echo " Eliminate all fetched comments that you do not have a"
|
|
." release\n";
|
|
echo " associated with.\n";
|
|
echo "\n";
|
|
echo " -b, --broadcast Broadast information for others so they can discover.\n";
|
|
echo "\n";
|
|
echo " -r, --soft-reset Safely resets sources as though they were\n";
|
|
echo " just added. This is ideal to do if you\n";
|
|
echo " change usenet servers.\n";
|
|
echo " -t, --test Produces a whole lot of garbage, but "
|
|
."is used for testing\n";
|
|
echo " the internals of the class...\n";
|
|
echo "\n";
|
|
}
|
|
|
|
if(!$options){ display_help(); exit(1);}
|
|
if(!count($options)){ display_help(); exit(1);}
|
|
|
|
$delete_broken_releases = false;
|
|
if(array_key_exists("G", $options) ||
|
|
array_key_exists("populate-fix-gid", $options)){
|
|
echo "Updating GID in releases table + fix ...";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->processGID(0,5000,true);
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("g", $options) ||
|
|
array_key_exists("populate-gid", $options)){
|
|
echo "Updating GID in releases table ...";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->processGID();
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("r", $options) ||
|
|
array_key_exists("soft-reset", $options)){
|
|
echo "Soft Reseting Spotnab... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->soft_reset();
|
|
echo "Done\n";
|
|
}
|
|
|
|
$force_keygen_save = false;
|
|
if(array_key_exists("K", $options) ||
|
|
array_key_exists("force-keygen", $options)){
|
|
$spotnab = new SpotNab();
|
|
$spotnab->keygen(true, true);
|
|
}
|
|
else if(array_key_exists("k", $options) ||
|
|
array_key_exists("keygen", $options)){
|
|
$spotnab = new SpotNab();
|
|
$spotnab->keygen(true);
|
|
}
|
|
|
|
if(array_key_exists("p", $options) ||
|
|
array_key_exists("post", $options)){
|
|
echo "Posting... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->post();
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("d", $options) ||
|
|
array_key_exists("discover", $options)){
|
|
echo "Discovering... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->fetch_discovery();
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("F", $options) ||
|
|
array_key_exists("fetch-backfill", $options)){
|
|
$days = array_key_exists("F", $options)?$options["F"]:$options["fetch-backfill"];
|
|
try{
|
|
$days = abs(intval($days));
|
|
}catch(Exception $e){
|
|
$days = -1;
|
|
}
|
|
|
|
if($days <= 0){
|
|
echo "Error: A SpotNab fetch backfill requires you specify the number of days to look back.\n";
|
|
echo "Syntax: php spontnab.php -F=<days>\n";
|
|
exit(1);
|
|
}
|
|
echo "Fetching $days day(s) back ... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->fetch(time()-($days*86400));
|
|
echo "Done\n";
|
|
|
|
|
|
}else if (array_key_exists("f", $options) ||
|
|
array_key_exists("fetch", $options)){
|
|
echo "Fetching... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->fetch();
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("b", $options) ||
|
|
array_key_exists("broadcast", $options)){
|
|
echo "Broadcasting... ";
|
|
$spotnab = new SpotNab();
|
|
$spotnab->post_discovery();
|
|
echo "Done\n";
|
|
}
|
|
|
|
if(array_key_exists("t", $options) ||
|
|
array_key_exists("test", $options)){
|
|
$spotnab = new SpotNab();
|
|
|
|
if($spotnab->has_openssl())
|
|
{
|
|
printf("%s INFO - Testing SSL Key Generator ...",
|
|
date("Y-m-d H:i:s"));
|
|
$keys = $spotnab->keygen(false);
|
|
if(is_array($keys) &&
|
|
array_key_exists("pubkey", $keys) &&
|
|
array_key_exists("prvkey", $keys))
|
|
{
|
|
$prvkey = $spotnab->decompstr($keys['prvkey']);
|
|
$pubkey = $spotnab->decompstr($keys['pubkey']);
|
|
$refc = $spotnab->getRandomStr(80);
|
|
$refd = $spotnab->decrypt($spotnab->encrypt($refc, $prvkey), $pubkey);
|
|
echo ($refc == $refd)?"Successful!\n":"Failed!\n";
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
|
|
printf("%s INFO - Testing SSL encryption/decryption ...",
|
|
date("Y-m-d H:i:s"));
|
|
$preMsg = $spotnab->getRandomStr(800);
|
|
$postMsg = $spotnab->decrypt($spotnab->encrypt($preMsg));
|
|
if($postMsg === false){
|
|
echo "Failed!\n";
|
|
}else if(!strcmp($preMsg, $postMsg)){
|
|
echo "Successful!\n";
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
|
|
printf("%s INFO - Testing small message encode/decode ...",
|
|
date("Y-m-d H:i:s"));
|
|
$before = array(
|
|
'server' => array(
|
|
'code' => 'l2g',
|
|
'title' => 'l2g newznab'
|
|
),
|
|
'postdate_utc' => $spotnab->local2utc(),
|
|
'comments' => array(
|
|
array(
|
|
'gid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'cid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'comment' => 'testing comment 1',
|
|
'username' => 'l2g',
|
|
'is_visible' => 1,
|
|
'postdate_utc' => $spotnab->local2utc(time()-86400)
|
|
),
|
|
array(
|
|
'gid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'cid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'username' => 'l2g-hater',
|
|
'is_visible' => 1,
|
|
'comment' => 'testing comment 2',
|
|
'postdate_utc' => $spotnab->local2utc(time()-86000)
|
|
)
|
|
)
|
|
);
|
|
$article = $spotnab->encodePost($before, Null, true);
|
|
if($article !== false){
|
|
$after = $spotnab->decodePost($article[1]);
|
|
if($before === $after){
|
|
echo "Successful!\n";
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
printf("%s INFO - Testing big message encode/decode ...",
|
|
date("Y-m-d H:i:s"));
|
|
$before = array(
|
|
'server' => array(
|
|
'code' => 'l2g',
|
|
'title' => 'l2g newznab'
|
|
),
|
|
'postdate_utc' => $spotnab->local2utc(),
|
|
'comments' => array()
|
|
);
|
|
for($i=0;$i<3000;$i++){
|
|
// Build large post
|
|
$before['comments'][] =array(
|
|
'gid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'cid' => 'ABCDEFHIJKLMNOPQRSTUVWXYZ0123456',
|
|
'comment' => $refc = $spotnab->getRandomStr(rand(15,200)),
|
|
'username' => 'bb',
|
|
'is_visible' => 1,
|
|
'postdate_utc' => $spotnab->local2utc(time()-86400)
|
|
);
|
|
}
|
|
$article = $spotnab->encodePost($before, Null, true);
|
|
if($article !== false){
|
|
$after = $spotnab->decodePost($article[1]);
|
|
if($before === $after){
|
|
echo "Successful!\n";
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
}else{
|
|
echo "Failed!\n";
|
|
}
|
|
|
|
printf("%s INFO - Testing fake usenet parse ...",
|
|
date("Y-m-d H:i:s"));
|
|
// Fake group hash table
|
|
$hash = array(array(
|
|
'ID' => 0,
|
|
'key' => $spotnab->decompstr($keys['pubkey']),
|
|
'user' => 'nntp',
|
|
'email' => 'spot@nntp.com',
|
|
// We want to find new content, so to make our header
|
|
// new, we need to take our ref time and back down
|
|
// one second so it can be processed..
|
|
'ref' => $article[2]['Epoch']-1
|
|
));
|
|
|
|
// Fake headers (use debug information from encodePost)
|
|
$headers = array($article[2]);
|
|
|
|
$matched = $spotnab->process_comment_headers($headers, $hash, false);
|
|
if($matched !== false){
|
|
$inserted = $matched[0];
|
|
$updated = $matched[1];
|
|
echo ($matched > 0)?"Successful!\n":"Failed!\n";
|
|
}else{
|
|
echo "Failed\n";
|
|
}
|
|
}else{
|
|
printf("%s WARNING - openssl is not correctly installed; broadcasts and posts will be disabled.\n",
|
|
date("Y-m-d H:i:s"));
|
|
}
|
|
|
|
printf("%s INFO - Testing UTC/Local conversions [1/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->utc2local();
|
|
$refb = $spotnab->utc2local($spotnab->local2utc($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
printf("%s INFO - Testing UTC/Local conversions [2/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->local2utc();
|
|
$refb = $spotnab->local2utc($spotnab->utc2local($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
printf("%s INFO - Testing UTC/Local conversions [3/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->local2utc(date("Y-m-d H:i:s"));
|
|
$refb = $spotnab->local2utc($spotnab->utc2local($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
printf("%s INFO - Testing UTC/Local conversions [4/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->utc2local(time());
|
|
$refb = $spotnab->utc2local($spotnab->local2utc($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
printf("%s INFO - Testing UTC/Local conversions [5/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->local2utc(time());
|
|
$refb = $spotnab->local2utc($spotnab->utc2local($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
printf("%s INFO - Testing UTC/Local conversions [6/6]...",
|
|
date("Y-m-d H:i:s"));
|
|
$refa = $spotnab->utc2local(gmdate("Y-m-d H:i:s"));
|
|
$refb = $spotnab->utc2local($spotnab->local2utc($refa));
|
|
echo ($refa == $refb)?"Successful!\n":"Failed!\n";
|
|
}
|
|
|
|
if(array_key_exists("o", $options) ||
|
|
array_key_exists("clean-orphan-comments", $options)){
|
|
echo "Removing orphan comments...";
|
|
$spotnab = new SpotNab();
|
|
printf("%d record(s) removed.\n", $spotnab->orphan_comment_clean());
|
|
} |