b31
This commit is contained in:
29
LICENSE.txt
Normal file
29
LICENSE.txt
Normal file
@ -0,0 +1,29 @@
|
||||
Copyright 2010 zzz (zzz@mail.i2p)
|
||||
|
||||
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
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
========================================================================
|
||||
Includes code from Jetty 5.1.15:
|
||||
|
||||
Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
||||
------------------------------------------------------------------------
|
||||
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
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
42
README.txt
Normal file
42
README.txt
Normal file
@ -0,0 +1,42 @@
|
||||
This is a very simple in-memory open tracker, wrapped into an I2P plugin.
|
||||
|
||||
The plugin starts a new http serer tunnel, eepsite, and Jetty server running at port 7662.
|
||||
The tracker status is available at http://127.0.0.1:7661/tracker/ .
|
||||
If other files are desired on the eepsite, they can be added at eepsite/docroot .
|
||||
|
||||
The open tracker code and jsps were written from scratch, but depend on some code
|
||||
in i2psnark.jar from the I2P installation for bencoding, and of course
|
||||
on other i2p libraries.
|
||||
See the license files in I2P for i2p and i2psnark licenses.
|
||||
There is also some code modified from Jetty 5.1.15.
|
||||
See LICENSES.txt for the zzzot and Jetty licenses.
|
||||
|
||||
I2P source must be installed and built in ../i2p.i2p to compile this package.
|
||||
|
||||
Sure, as a standalone program in its own JVM with Jetty, this would be a pig -
|
||||
you should use the C opentracker instead. But since you're already running
|
||||
the JVM and Jetty, running this in the same JVM probably doesn't hog to much more memory.
|
||||
|
||||
Valid announce URLs:
|
||||
/a
|
||||
/announce
|
||||
/announce.jsp
|
||||
/announce.php
|
||||
/tracker/a
|
||||
/tracker/announce
|
||||
/tracker/announce.jsp
|
||||
/tracker/announce.php
|
||||
|
||||
Valid scrape URLs:
|
||||
/scrape
|
||||
/scrape.jsp
|
||||
/scrape.php
|
||||
/tracker/scrape
|
||||
/tracker/scrape.jsp
|
||||
/tracker/scrape.php
|
||||
|
||||
The tracker also responds to seedless queries at
|
||||
/Seedless/index.jsp
|
||||
|
||||
You may use the rest of the eepsite for other purposes, for example you
|
||||
may place torrent files in eepsite/docroot/torrents.
|
19
TODO.txt
Normal file
19
TODO.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Configuration file:
|
||||
- interval
|
||||
- clean time
|
||||
- max peers in response
|
||||
- disable full scrapes
|
||||
- disable all scrapes
|
||||
- disable seedless
|
||||
|
||||
Stop the cleaner
|
||||
|
||||
Throttles:
|
||||
- full scrapes
|
||||
- per-requestor
|
||||
|
||||
Bans:
|
||||
- refuse non-GETs
|
||||
|
||||
Verifier:
|
||||
- Check dest vs. b32 in header
|
67
build.xml
Normal file
67
build.xml
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project basedir="." default="all" name="zzzot">
|
||||
|
||||
<target name="all" depends="clean,plugin" />
|
||||
|
||||
<target name="war" >
|
||||
<ant dir="src" target="build" />
|
||||
</target>
|
||||
|
||||
<target name="plugin" depends="war">
|
||||
<delete file="plugin/i2ptunnel.config" />
|
||||
<!-- get version number -->
|
||||
<buildnumber file="scripts/build.number" />
|
||||
<property name="release.number" value="0.1" />
|
||||
|
||||
<!-- make the update xpi2p -->
|
||||
<!-- this contains everything except i2ptunnel.config -->
|
||||
<copy file="LICENSE.txt" todir="plugin/" overwrite="true" />
|
||||
<copy file="README.txt" todir="plugin/" overwrite="true" />
|
||||
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
|
||||
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||
<arg value="update-only=true" />
|
||||
</exec>
|
||||
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||
<arg value="version=${release.number}-b${build.number}" />
|
||||
</exec>
|
||||
<exec executable="pack200" failonerror="true">
|
||||
<arg value="-g" />
|
||||
<arg value="plugin/lib/zzzot.jar.pack" />
|
||||
<arg value="src/build/zzzot.jar" />
|
||||
</exec>
|
||||
<exec executable="pack200" failonerror="true">
|
||||
<arg value="-g" />
|
||||
<arg value="plugin/eepsite/webapps/tracker.war.pack" />
|
||||
<arg value="src/build/tracker.war.jar" />
|
||||
</exec>
|
||||
<exec executable="scripts/makeplugin.sh" failonerror="true" >
|
||||
<arg value="plugin" />
|
||||
</exec>
|
||||
<move file="zzzot.xpi2p" tofile="zzzot-update.xpi2p" overwrite="true" />
|
||||
|
||||
<!-- make the install xpi2p -->
|
||||
<copy file="scripts/i2ptunnel.config" todir="plugin/" overwrite="true" />
|
||||
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
|
||||
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||
<arg value="version=${release.number}-b${build.number}" />
|
||||
</exec>
|
||||
<exec executable="scripts/makeplugin.sh" failonerror="true" >
|
||||
<arg value="plugin" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="distclean" depends="clean" />
|
||||
|
||||
<target name="clean" >
|
||||
<ant dir="src" target="clean" />
|
||||
<delete file="plugin/i2ptunnel.config" />
|
||||
<delete file="plugin/plugin.config" />
|
||||
<delete file="plugin/lib/zzzot.jar.pack" />
|
||||
<delete file="plugin/eepsite/webapps/tracker.war.pack" />
|
||||
<delete file="plugin/LICENSE.txt" />
|
||||
<delete file="plugin/README.txt" />
|
||||
<delete file="zzzot.xpi2p" />
|
||||
<delete file="zzzot-update.xpi2p" />
|
||||
</target>
|
||||
|
||||
</project>
|
8
plugin/clients.config
Normal file
8
plugin/clients.config
Normal file
@ -0,0 +1,8 @@
|
||||
clientApp.0.main=net.i2p.zzzot.ZzzOTController
|
||||
clientApp.0.name=ZzzOT
|
||||
clientApp.0.args=-d $PLUGIN start
|
||||
clientApp.0.stopargs=-d $PLUGIN stop
|
||||
clientApp.0.delay=15
|
||||
clientApp.0.startOnLoad=true
|
||||
# we also use i2p.jar and i2ptunnel.jar, they are in the standard router classpath
|
||||
clientApp.0.classpath=$PLUGIN/lib/zzzot.jar,$I2P/lib/i2psnark.jar
|
6
plugin/eepsite/docroot/index.html
Normal file
6
plugin/eepsite/docroot/index.html
Normal file
@ -0,0 +1,6 @@
|
||||
<html><head>
|
||||
<!-- edit this file if you want to change your home page -->
|
||||
<title>zzzot</title>
|
||||
</head><body style="background-color: #000; color: #c30; font-size: 2000%;">
|
||||
<center><b>zzzot</b></center>
|
||||
</body></html>
|
2
plugin/eepsite/docroot/robots.txt
Normal file
2
plugin/eepsite/docroot/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
56
plugin/templates/help.html
Normal file
56
plugin/templates/help.html
Normal file
@ -0,0 +1,56 @@
|
||||
<html><head><title>ZzzOT Plugin Help</title></head>
|
||||
<body style="background-color: #ddd; color: #a30;">
|
||||
<h2>Welcome to the ZzzOT I2P Plugin!</h2>
|
||||
|
||||
A new eepsite tunnel and Jetty server have been started for your open tracker.
|
||||
|
||||
<p><a href="/tracker/index.jsp">Click here to see the current stats</a>.
|
||||
This link is also at the top of your router console when ZzzOT is running.
|
||||
|
||||
<p>Report bugs or add comments on
|
||||
<a href="htp://zzz.i2p//forums/16">the plugin forum on zzz.i2p</a>.
|
||||
|
||||
<h3>Eepsite Key and Helpful Hints for I2P</h3>
|
||||
|
||||
<p>Your Base 32 address is <a href="http://$B32/">$B32</a>.
|
||||
Others may access your eepsite using this address, even if you do not publish a hostname.
|
||||
<p>Once you decide on a host name, you may
|
||||
<a href="http://127.0.0.1:7657/susidns/addressbook.jsp?book=private&destination=$B64">add the key to your local addressbook here</a>.
|
||||
<p>Your Base 64 key is: <textarea rows="1" style="height: 3em;" cols="40" readonly="readonly" wrap="off">$B64</textarea>
|
||||
<br>You will need this key to register a hostname at <a href="http://stats.i2p/i2p/addkey.html">stats.i2p</a>.
|
||||
<p>Your private key file is $PLUGIN/eepPriv.dat - back it up!!!
|
||||
<p>Your eepsite document root is $PLUGIN/eepsite/docroot,
|
||||
you may put other files there is you wish to have additional content on your eepsite.
|
||||
<p>The supported announce URLs are:
|
||||
<ul>
|
||||
<li><a href="http://$B32/a">http://$B32/a</a>
|
||||
<li><a href="http://$B32/announce">http://$B32/announce</a>
|
||||
<li><a href="http://$B32/announce.jsp">http://$B32/announce.jsp</a>
|
||||
<li><a href="http://$B32/announce.php">http://$B32/announce.php</a>
|
||||
<li><a href="http://$B32/tracker/a">http://$B32/tracker/a</a>
|
||||
<li><a href="http://$B32/tracker/announce">http://$B32/tracker/announce</a>
|
||||
<li><a href="http://$B32/tracker/announce.jsp">http://$B32/tracker/announce.jsp</a>
|
||||
<li><a href="http://$B32/tracker/announce.php">http://$B32/tracker/announce.php</a>
|
||||
</ul>
|
||||
<p>The supported scrape URLs are:
|
||||
<ul>
|
||||
<li><a href="http://$B32/scrape">http://$B32/scrape</a>
|
||||
<li><a href="http://$B32/scrape.jsp">http://$B32/scrape.jsp</a>
|
||||
<li><a href="http://$B32/scrape.php">http://$B32/scrape.php</a>
|
||||
<li><a href="http://$B32/tracker/scrape">http://$B32/tracker/scrape</a>
|
||||
<li><a href="http://$B32/tracker/scrape.jsp">http://$B32/tracker/scrape.jsp</a>
|
||||
<li><a href="http://$B32/tracker/scrape.php">http://$B32/tracker/scrape.php</a>
|
||||
</ul>
|
||||
<p>Your eepsite tunnel is configured for 2 inbound and 2 outbound tunnels, 3 hops each.
|
||||
You may change tunnel settings by editing $PLUGIN/i2ptunnel.config and restarting the plugin.
|
||||
The tunnel will not appear in <a href="http://127.0.0.1:7657/i2ptunnel/index.jsp">i2ptunnel</a>.
|
||||
If your tracker gets over 1000 peers, you will probably want to increase the number of tunnels.
|
||||
<p>The Jetty webserver port is 7662. If you must change it, edit jetty.xml, i2ptunnel.config, and plugins.config
|
||||
in the directory $PLUGIN. Then stop and restart the plugin.
|
||||
<p>This help file is $PLUGIN/eepsite/docroot/help.html, you should probably move it
|
||||
outside of the document root before you announce your eepsite as it may contain your user name.
|
||||
<p>As you probably know, an open tracker does not require torrents to be registered,
|
||||
and it does not host torrent files. You can, however, host torrent files elsewhere on
|
||||
the eepsite, for example at <a href="http://$B32/torrents/">/torrents</a>.
|
||||
|
||||
</body></html>
|
186
plugin/templates/jetty.xml
Normal file
186
plugin/templates/jetty.xml
Normal file
@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
||||
|
||||
<!-- ========================================================================= -->
|
||||
<!-- This file configures the Jetty server. -->
|
||||
<!-- All changes require a restart of I2P. -->
|
||||
<!-- -->
|
||||
<!-- Commonly changed settings: -->
|
||||
<!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section -->
|
||||
<!-- to access the server directly (bypassing i2p) -->
|
||||
<!-- from other computers. The included version of Jetty has -->
|
||||
<!-- been patched to allow IPv6 addresses as well, -->
|
||||
<!-- enclosed in brackets e.g. [::1] -->
|
||||
<!-- * port: Default 7662 in the addListener section -->
|
||||
<!-- * threads: Raise MaxThreads in the addListener section -->
|
||||
<!-- if you have a high-traffic site and get a lot of warnings. -->
|
||||
<!-- -->
|
||||
<!-- I2P uses Jetty 5.1.15. We have no plans to upgrade to Jetty 6, due to -->
|
||||
<!-- the significant changes in the API. If you need web server features not -->
|
||||
<!-- found in Jetty 5, you may install and run Jetty 6 in a different JVM, -->
|
||||
<!-- or run any other web server such as Apache. If you do run another -->
|
||||
<!-- web server instead, be sure and disable the Jetty 5 server for your -->
|
||||
<!-- eepsite on http://127.0.0.1/configclients.jsp . -->
|
||||
<!-- -->
|
||||
<!-- Jetty errors and warnings will appear in wrapper.log, check there -->
|
||||
<!-- to diagnose problems. -->
|
||||
<!-- ========================================================================= -->
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Jetty Server -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure class="org.mortbay.jetty.Server">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Request Listeners -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add and configure a HTTP listener to port 8080 -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.SocketListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.util.InetAddrPort">
|
||||
<Set name="host">127.0.0.1</Set>
|
||||
<Set name="port">7662</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MaxThreads">10</Set>
|
||||
<Set name="MaxIdleTimeMs">60000</Set>
|
||||
<Set name="LowResourcePersistTimeMs">1000</Set>
|
||||
<Set name="ConfidentialPort">8443</Set>
|
||||
<Set name="IntegralPort">8443</Set>
|
||||
<Set name="PoolName">main</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Contexts -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a all web application within the webapps directory. -->
|
||||
<!-- + No virtual host specified -->
|
||||
<!-- + Look in the webapps directory relative to jetty.home or . -->
|
||||
<!-- + Use the default webdefault.xml in jetty's install -->
|
||||
<!-- + Upack the war file -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Set name="rootWebApp">root</Set>
|
||||
<Call name="addWebApplications">
|
||||
<Arg></Arg>
|
||||
<Arg>$PLUGIN/eepsite/webapps/</Arg>
|
||||
<Arg></Arg>
|
||||
<Arg type="boolean">true</Arg>
|
||||
</Call>
|
||||
|
||||
<Call name="addContext">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.HttpContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="resourceBase">$PLUGIN/eepsite/docroot</Set>
|
||||
<Call name="addHandler">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.handler.ResourceHandler">
|
||||
<Set name="redirectWelcome">FALSE</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<!-- This custom handler is like Jetty's ForwardHandler,
|
||||
- but it passes CGI query parameters through.
|
||||
- Note that it is somewhat misnamed - it does NOT
|
||||
- return a 301/302, it handles the request directly.
|
||||
-->
|
||||
<Call name="addHandler">
|
||||
<Arg>
|
||||
<New class="net.i2p.zzzot.QForwardHandler">
|
||||
<Call name="setHandleQueries">
|
||||
<Arg type="boolean">true</Arg>
|
||||
</Call>
|
||||
<!-- Forward announce requests to /tracker/announce.jsp -->
|
||||
<Call name="addForward">
|
||||
<Arg>/a</Arg>
|
||||
<Arg>/tracker/announce.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/announce</Arg>
|
||||
<Arg>/tracker/announce.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/announce.jsp</Arg>
|
||||
<Arg>/tracker/announce.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/announce.php</Arg>
|
||||
<Arg>/tracker/announce.jsp</Arg>
|
||||
</Call>
|
||||
<!-- Forward scrape requests to /tracker/scrape.jsp -->
|
||||
<Call name="addForward">
|
||||
<Arg>/scrape</Arg>
|
||||
<Arg>/tracker/scrape.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/scrape.jsp</Arg>
|
||||
<Arg>/tracker/scrape.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/scrape.php</Arg>
|
||||
<Arg>/tracker/scrape.jsp</Arg>
|
||||
</Call>
|
||||
<!-- Forward Seedless requests to /tracker/seedless.jsp -->
|
||||
<Call name="addForward">
|
||||
<Arg>/Seedless</Arg>
|
||||
<Arg>/tracker/seedless.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/Seedless/</Arg>
|
||||
<Arg>/tracker/seedless.jsp</Arg>
|
||||
</Call>
|
||||
<Call name="addForward">
|
||||
<Arg>/Seedless/index.jsp</Arg>
|
||||
<Arg>/tracker/seedless.jsp</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<Call name="addContext">
|
||||
<Arg>/cgi-bin/*</Arg>
|
||||
<Set name="ResourceBase">$PLUGIN/eepsite/cgi-bin</Set>
|
||||
<Call name="addServlet">
|
||||
<Arg>Common Gateway Interface</Arg>
|
||||
<Arg>/</Arg>
|
||||
<Arg>org.mortbay.servlet.CGI</Arg>
|
||||
<Put name="Path">/usr/local/bin:/usr/ucb:/bin:/usr/bin</Put>
|
||||
</Call>
|
||||
</Call>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Request Log -->
|
||||
<!-- =============================================================== -->
|
||||
<Set name="RequestLog">
|
||||
<New class="org.mortbay.http.I2PRequestLog">
|
||||
<Arg>$PLUGIN/eepsite/logs/yyyy_mm_dd.request.log</Arg>
|
||||
<Set name="retainDays">30</Set>
|
||||
<Set name="append">true</Set>
|
||||
<Set name="extended">false</Set>
|
||||
<Set name="buffered">false</Set>
|
||||
<Set name="LogTimeZone">GMT</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Other Server Options -->
|
||||
<!-- =============================================================== -->
|
||||
<Set name="requestsPerGC">2000</Set>
|
||||
<Set name="statsOn">false</Set>
|
||||
|
||||
</Configure>
|
25
scripts/i2ptunnel.config
Normal file
25
scripts/i2ptunnel.config
Normal file
@ -0,0 +1,25 @@
|
||||
tunnel.0.description=ZzzOT
|
||||
tunnel.0.i2cpHost=127.0.0.1
|
||||
tunnel.0.i2cpPort=7654
|
||||
tunnel.0.name=zzzot
|
||||
tunnel.0.option.i2cp.enableAccessList=false
|
||||
tunnel.0.option.i2cp.encryptLeaseSet=false
|
||||
tunnel.0.option.i2cp.reduceIdleTime=1200000
|
||||
tunnel.0.option.i2cp.reduceOnIdle=true
|
||||
tunnel.0.option.i2cp.reduceQuantity=1
|
||||
tunnel.0.option.i2p.streaming.connectDelay=0
|
||||
tunnel.0.option.inbound.backupQuantity=0
|
||||
tunnel.0.option.inbound.length=3
|
||||
tunnel.0.option.inbound.lengthVariance=0
|
||||
tunnel.0.option.inbound.nickname=ZzzOT
|
||||
tunnel.0.option.inbound.quantity=2
|
||||
tunnel.0.option.outbound.backupQuantity=0
|
||||
tunnel.0.option.outbound.length=3
|
||||
tunnel.0.option.outbound.lengthVariance=0
|
||||
tunnel.0.option.outbound.nickname=ZzzOT
|
||||
tunnel.0.option.outbound.quantity=2
|
||||
tunnel.0.privKeyFile=plugins/zzzot/eepPriv.dat
|
||||
tunnel.0.startOnLoad=true
|
||||
tunnel.0.targetHost=127.0.0.1
|
||||
tunnel.0.targetPort=7662
|
||||
tunnel.0.type=httpserver
|
104
scripts/makeplugin.sh
Executable file
104
scripts/makeplugin.sh
Executable file
@ -0,0 +1,104 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# basic packaging up of a plugin
|
||||
#
|
||||
# usage: makeplugin.sh plugindir
|
||||
#
|
||||
# zzz 2010-02
|
||||
#
|
||||
PUBKEYDIR=$HOME/.i2p-plugin-keys
|
||||
PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key
|
||||
PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key
|
||||
B64KEYFILE=$PUBKEYDIR/plugin-public-signing.txt
|
||||
export I2P=../i2p/pkg-temp
|
||||
|
||||
PLUGINDIR=${1:-plugin}
|
||||
|
||||
PC=plugin.config
|
||||
PCT=${PC}.tmp
|
||||
|
||||
if [ ! -f $PRIVKEYFILE ]
|
||||
then
|
||||
mkdir -p $PUBKEYDIR
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate keygen $PUBKEYFILE $PRIVKEYFILE || exit 1
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.data.Base64 encode $PUBKEYFILE $B64KEYFILE || exit 1
|
||||
rm -rf logs/
|
||||
chmod 444 $PUBKEYFILE $B64KEYFILE
|
||||
chmod 400 $PRIVKEYFILE
|
||||
echo "Created new keys: $PUBKEYFILE $PRIVKEYFILE"
|
||||
fi
|
||||
|
||||
rm -f plugin.zip
|
||||
if [ ! -d $PLUGINDIR ]
|
||||
then
|
||||
echo "You must have a $PLUGINDIR directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OPWD=$PWD
|
||||
cd $PLUGINDIR
|
||||
|
||||
if [ ! -f $PC ]
|
||||
then
|
||||
echo "You must have a $PC file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q '^signer=' $PC
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a signer in $PC"
|
||||
echo 'For example signer=joe@mail.i2p'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q '^name=' $PC
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a plugin name in $PC"
|
||||
echo 'For example name=foo'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -q '^version=' $PC
|
||||
if [ "$?" -ne "0" ]
|
||||
then
|
||||
echo "You must have a version in $PC"
|
||||
echo 'For example version=0.1.2'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# update the date
|
||||
grep -v '^date=' $PC > $PCT
|
||||
DATE=`date '+%s000'`
|
||||
echo "date=$DATE" >> $PCT
|
||||
mv $PCT $PC
|
||||
|
||||
# add our Base64 key
|
||||
grep -v '^key=' $PC > $PCT
|
||||
B64KEY=`cat $B64KEYFILE`
|
||||
echo "key=$B64KEY" >> $PCT || exit 1
|
||||
mv $PCT $PC
|
||||
|
||||
# zip it
|
||||
zip -r $OPWD/plugin.zip * -x \*.jar || exit 1
|
||||
|
||||
# get the version and use it for the sud header
|
||||
VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
|
||||
# get the name and use it for the file name
|
||||
NAME=`grep '^name=' $PC | cut -f 2 -d '='`
|
||||
XPI2P=${NAME}.xpi2p
|
||||
cd $OPWD
|
||||
|
||||
# sign it
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign plugin.zip $XPI2P $PRIVKEYFILE $VERSION || exit 1
|
||||
rm -f plugin.zip
|
||||
|
||||
# verify
|
||||
echo 'Verifying. ...'
|
||||
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion $XPI2P || exit 1
|
||||
java -cp $I2P/lib/i2p.jar -Drouter.trustedUpdateKeys=$B64KEY net.i2p.crypto.TrustedUpdate verifysig $XPI2P || exit 1
|
||||
rm -rf logs/
|
||||
|
||||
echo -n 'Plugin created: '
|
||||
wc -c $XPI2P
|
8
scripts/plugin.config
Normal file
8
scripts/plugin.config
Normal file
@ -0,0 +1,8 @@
|
||||
name=zzzot
|
||||
signer=zzz-plugin@mail.i2p
|
||||
consoleLinkName=ZzzOT
|
||||
consoleLinkURL=http://127.0.0.1:7662/tracker/index.jsp
|
||||
description=Open tracker
|
||||
author=zzz
|
||||
updateURL=http://stats.i2p/i2p/plugins/zzzot-update.xpi2p
|
||||
license=Apache 2.0
|
116
src/build.xml
Normal file
116
src/build.xml
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="i2psnark">
|
||||
<property name="i2pbase" value="../../i2p.i2p"/>
|
||||
<property name="i2plib" value="${i2pbase}/build"/>
|
||||
<property name="jettylib" value="${i2pbase}/apps/jetty/jettylib"/>
|
||||
<property name="war" value="../plugin/eepsite/webapps/blog"/>
|
||||
<property name="lib" value="${war}/WEB-INF/lib"/>
|
||||
<path id="cp">
|
||||
<pathelement path="${java.class.path}" />
|
||||
<pathelement location="${i2plib}/i2p.jar" />
|
||||
<pathelement location="${i2plib}/i2ptunnel.jar" />
|
||||
<pathelement location="${i2plib}/i2psnark.jar" />
|
||||
<pathelement location="${i2plib}/routerconsole.jar" />
|
||||
<pathelement location="${jettylib}/ant.jar"/>
|
||||
<pathelement location="${jettylib}/org.mortbay.jetty.jar"/>
|
||||
<pathelement location="${jettylib}/jasper-compiler.jar" />
|
||||
<pathelement location="${jettylib}/jasper-runtime.jar" />
|
||||
<pathelement location="${jettylib}/javax.servlet.jar" />
|
||||
<pathelement location="${jettylib}/commons-logging.jar" />
|
||||
<pathelement location="${jettylib}/commons-el.jar" />
|
||||
</path>
|
||||
|
||||
<target name="all" depends="clean, build" />
|
||||
<target name="build" depends="jar, war" />
|
||||
<target name="builddep">
|
||||
</target>
|
||||
<condition property="depend.available">
|
||||
<typefound name="depend" />
|
||||
</condition>
|
||||
<target name="depend" if="depend.available">
|
||||
<depend
|
||||
cache="build"
|
||||
srcdir="./src"
|
||||
destdir="./build/obj" >
|
||||
<!-- Depend on classes instead of jars where available -->
|
||||
<classpath>
|
||||
<pathelement location="../../../core/java/build/obj" />
|
||||
<pathelement location="../../ministreaming/java/build/obj" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
</classpath>
|
||||
</depend>
|
||||
</target>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
|
||||
<target name="compile" depends="depend">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
<javac
|
||||
srcdir="./java"
|
||||
debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
destdir="./build/obj"
|
||||
classpath="${i2plib}/i2p.jar:${i2plib}/i2ptunnel.jar:${i2plib}/i2psnark.jar:${i2plib}/systray.jar:${i2plib}/org.mortbay.jetty.jar" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="builddep, compile">
|
||||
<jar destfile="build/zzzot.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="precompilejsp" depends="compile" >
|
||||
<mkdir dir="build" />
|
||||
<mkdir dir="build/war/WEB-INF/classes" />
|
||||
<path id="jspcp">
|
||||
<path refid="cp" />
|
||||
<pathelement location="build/obj" />
|
||||
</path>
|
||||
<java classname="org.apache.jasper.JspC" fork="true" classpathref="jspcp" failonerror="true">
|
||||
<arg value="-d" />
|
||||
<arg value="build/jspjava" />
|
||||
<arg value="-v" />
|
||||
<arg value="-p" />
|
||||
<arg value="net.i2p.zzzot" />
|
||||
<arg value="-webinc" />
|
||||
<arg value="build/web-fragment.xml" />
|
||||
<arg value="-webapp" />
|
||||
<arg value="jsp/" />
|
||||
</java>
|
||||
|
||||
<javac
|
||||
debug="true"
|
||||
deprecation="on"
|
||||
source="1.5" target="1.5"
|
||||
destdir="build/war/WEB-INF/classes"
|
||||
srcdir="./build/jspjava"
|
||||
includes="**/*.java"
|
||||
classpathref="jspcp"
|
||||
failonerror="true" />
|
||||
|
||||
<copy file="jsp/WEB-INF/web.xml" tofile="build/web.xml" />
|
||||
<loadfile property="jspc.web.fragment" srcfile="build/web-fragment.xml" />
|
||||
<replace file="build/web.xml">
|
||||
<replacefilter token="<!-- precompiled servlets -->" value="${jspc.web.fragment}" />
|
||||
</replace>
|
||||
|
||||
</target>
|
||||
|
||||
<target name="war" depends="precompilejsp">
|
||||
<copy file="jsp/index.html" todir="build/war" />
|
||||
<war destfile="build/tracker.war.jar" webxml="build/web.xml">
|
||||
<fileset dir="build/war" />
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="./build" />
|
||||
</target>
|
||||
|
||||
<target name="cleandep" depends="clean">
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
</target>
|
||||
</project>
|
37
src/java/net/i2p/zzzot/InfoHash.java
Normal file
37
src/java/net/i2p/zzzot/InfoHash.java
Normal file
@ -0,0 +1,37 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.i2p.data.ByteArray;
|
||||
|
||||
/**
|
||||
* A 20-byte SHA1 info hash
|
||||
*/
|
||||
public class InfoHash extends ByteArray {
|
||||
|
||||
public InfoHash(String data) throws UnsupportedEncodingException {
|
||||
this(data.getBytes("ISO-8859-1"));
|
||||
}
|
||||
|
||||
public InfoHash(byte[] data) {
|
||||
super(data);
|
||||
if (data.length != 20)
|
||||
throw new IllegalArgumentException("Bad infohash length: " + data.length);
|
||||
}
|
||||
}
|
37
src/java/net/i2p/zzzot/PID.java
Normal file
37
src/java/net/i2p/zzzot/PID.java
Normal file
@ -0,0 +1,37 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.i2p.data.ByteArray;
|
||||
|
||||
/**
|
||||
* A 20-byte peer ID
|
||||
*/
|
||||
public class PID extends ByteArray {
|
||||
|
||||
public PID(String data) throws UnsupportedEncodingException {
|
||||
this(data.getBytes("ISO-8859-1"));
|
||||
}
|
||||
|
||||
public PID(byte[] data) {
|
||||
super(data);
|
||||
if (data.length != 20)
|
||||
throw new IllegalArgumentException("Bad peer ID length: " + data.length);
|
||||
}
|
||||
}
|
58
src/java/net/i2p/zzzot/Peer.java
Normal file
58
src/java/net/i2p/zzzot/Peer.java
Normal file
@ -0,0 +1,58 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
|
||||
/*
|
||||
* A single peer for a single torrent.
|
||||
* Save a couple stats, and implements
|
||||
* a Map so we can BEncode it
|
||||
* So it's like PeerID but in reverse - we make a Map from the
|
||||
* data. PeerID makes the data from a Map.
|
||||
*/
|
||||
public class Peer extends HashMap<String, Object> {
|
||||
|
||||
private long lastSeen;
|
||||
private long bytesLeft;
|
||||
private static final Integer PORT = Integer.valueOf(6881);
|
||||
|
||||
public Peer(byte[] id, Destination address) {
|
||||
super(3);
|
||||
if (id.length != 20)
|
||||
throw new IllegalArgumentException("Bad peer ID length: " + id.length);
|
||||
put("peer id", id);
|
||||
put("ip", address.toBase64() + ".i2p");
|
||||
put("port", PORT);
|
||||
}
|
||||
|
||||
public void setLeft(long l) {
|
||||
bytesLeft = l;
|
||||
lastSeen = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean isSeed() {
|
||||
return bytesLeft <= 0;
|
||||
}
|
||||
|
||||
public long lastSeen() {
|
||||
return lastSeen;
|
||||
}
|
||||
}
|
42
src/java/net/i2p/zzzot/Peers.java
Normal file
42
src/java/net/i2p/zzzot/Peers.java
Normal file
@ -0,0 +1,42 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* All the peers for a single torrent
|
||||
*/
|
||||
public class Peers extends ConcurrentHashMap<PID, Peer> {
|
||||
|
||||
public Peers() {
|
||||
super();
|
||||
}
|
||||
|
||||
public int countSeeds() {
|
||||
int rv = 0;
|
||||
for (Peer p : values()) {
|
||||
if (p.isSeed())
|
||||
rv++;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public int countLeeches() {
|
||||
return size() - countSeeds();
|
||||
}
|
||||
}
|
158
src/java/net/i2p/zzzot/QForwardHandler.java
Normal file
158
src/java/net/i2p/zzzot/QForwardHandler.java
Normal file
@ -0,0 +1,158 @@
|
||||
// ========================================================================
|
||||
// $Id: ForwardHandler.java,v 1.16 2005/08/13 00:01:26 gregwilkins Exp $
|
||||
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// 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
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package net.i2p.zzzot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mortbay.http.HttpException;
|
||||
import org.mortbay.http.HttpMessage;
|
||||
import org.mortbay.http.HttpRequest;
|
||||
import org.mortbay.http.HttpResponse;
|
||||
import org.mortbay.http.PathMap;
|
||||
import org.mortbay.http.handler.AbstractHttpHandler;
|
||||
import org.mortbay.util.URI;
|
||||
import org.mortbay.util.UrlEncoded;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Forward Request Handler.
|
||||
* Forwards a request to a new URI. Experimental - use with caution.
|
||||
* @version $Revision: 1.16 $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*
|
||||
* Just like ForwardHandler but forwards query parameters too
|
||||
* And took out the dependency on apache logging
|
||||
* @author zzz
|
||||
*/
|
||||
public class QForwardHandler extends AbstractHttpHandler
|
||||
{
|
||||
PathMap _forward = new PathMap();
|
||||
String _root;
|
||||
boolean _handleQueries = false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
*/
|
||||
public QForwardHandler()
|
||||
{}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param rootForward
|
||||
*/
|
||||
public QForwardHandler(String rootForward)
|
||||
{
|
||||
_root=rootForward;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add a forward mapping.
|
||||
* @param pathSpecInContext The path to forward from
|
||||
* @param newPath The path to forward to.
|
||||
*/
|
||||
public void addForward(String pathSpecInContext,
|
||||
String newPath)
|
||||
{
|
||||
_forward.put(pathSpecInContext,newPath);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add a forward mapping for root path.
|
||||
* This allows a forward for exactly / which is the default
|
||||
* path in a pathSpec.
|
||||
* @param newPath The path to forward to.
|
||||
*/
|
||||
public void setRootForward(String newPath)
|
||||
{
|
||||
_root=newPath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the Handler up to cope with forwards to paths that contain query
|
||||
* elements (e.g. "/blah"->"/foo?a=b").
|
||||
* AND (I2P) pass params through (e.g. "/blah?c=d? -> "/foo?c=d? ).
|
||||
* @param b
|
||||
*/
|
||||
public void setHandleQueries(boolean b)
|
||||
{
|
||||
_handleQueries = b;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String pathInContext,
|
||||
String pathParams,
|
||||
HttpRequest request,
|
||||
HttpResponse response)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
String newPath=null;
|
||||
String query=null;
|
||||
if (_root!=null && ("/".equals(pathInContext) || pathInContext.startsWith("/;")))
|
||||
newPath=_root;
|
||||
else
|
||||
{
|
||||
Map.Entry entry = _forward.getMatch(pathInContext);
|
||||
if (entry!=null)
|
||||
{
|
||||
String match = (String)entry.getValue();
|
||||
if (_handleQueries)
|
||||
{
|
||||
int hook = match.indexOf('?');
|
||||
if (hook != -1){
|
||||
query = match.substring(hook+1);
|
||||
match = match.substring(0, hook);
|
||||
}
|
||||
}
|
||||
String info=PathMap.pathInfo((String)entry.getKey(),pathInContext);
|
||||
newPath=info==null?match:(URI.addPaths(match,info));
|
||||
}
|
||||
}
|
||||
|
||||
if (newPath!=null)
|
||||
{
|
||||
// this is the new part for i2p
|
||||
// setPath() changes the request URI and loses the parameters
|
||||
// so save them and add them back
|
||||
Map saved = null;
|
||||
if (_handleQueries){
|
||||
request.setCharacterEncoding("ISO-8859-1", false);
|
||||
saved = request.getParameters();
|
||||
}
|
||||
|
||||
int last=request.setState(HttpMessage.__MSG_EDITABLE);
|
||||
String context=getHttpContext().getContextPath();
|
||||
if (context.length()==1)
|
||||
request.setPath(newPath);
|
||||
else
|
||||
request.setPath(URI.addPaths(context,newPath));
|
||||
if (_handleQueries && query != null){
|
||||
// add forwarded to query string to parameters
|
||||
UrlEncoded.decodeTo(query, request.getParameters());
|
||||
}
|
||||
|
||||
// this is the new part for i2p
|
||||
if (_handleQueries){
|
||||
// add them back
|
||||
request.getParameters().putAll(saved);
|
||||
}
|
||||
|
||||
request.setState(last);
|
||||
getHttpContext().getHttpServer().service(request,response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
37
src/java/net/i2p/zzzot/Torrents.java
Normal file
37
src/java/net/i2p/zzzot/Torrents.java
Normal file
@ -0,0 +1,37 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* All the torrents
|
||||
*/
|
||||
public class Torrents extends ConcurrentHashMap<InfoHash, Peers> {
|
||||
|
||||
public Torrents() {
|
||||
super();
|
||||
}
|
||||
|
||||
public int countPeers() {
|
||||
int rv = 0;
|
||||
for (Peers p : values()) {
|
||||
rv += p.size();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
66
src/java/net/i2p/zzzot/ZzzOT.java
Normal file
66
src/java/net/i2p/zzzot/ZzzOT.java
Normal file
@ -0,0 +1,66 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
/**
|
||||
* Instantiate this to fire it up
|
||||
*/
|
||||
class ZzzOT {
|
||||
|
||||
private Torrents _torrents;
|
||||
private static final long CLEAN_TIME = 4*60*1000;
|
||||
private static final long EXPIRE_TIME = 60*60*1000;
|
||||
|
||||
ZzzOT() {
|
||||
_torrents = new Torrents();
|
||||
SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
|
||||
}
|
||||
|
||||
Torrents getTorrents() {
|
||||
return _torrents;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_torrents.clear();
|
||||
// no way to stop the cleaner
|
||||
}
|
||||
|
||||
private class Cleaner implements SimpleTimer.TimedEvent {
|
||||
|
||||
public void timeReached() {
|
||||
long now = System.currentTimeMillis();
|
||||
for (Iterator<Peers> iter = _torrents.values().iterator(); iter.hasNext(); ) {
|
||||
Peers p = iter.next();
|
||||
int recent = 0;
|
||||
for (Iterator<Peer> iterp = p.values().iterator(); iterp.hasNext(); ) {
|
||||
Peer peer = iterp.next();
|
||||
if (peer.lastSeen() < now - EXPIRE_TIME)
|
||||
iterp.remove();
|
||||
else
|
||||
recent++;
|
||||
}
|
||||
if (recent <= 0)
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
229
src/java/net/i2p/zzzot/ZzzOTController.java
Normal file
229
src/java/net/i2p/zzzot/ZzzOTController.java
Normal file
@ -0,0 +1,229 @@
|
||||
package net.i2p.zzzot;
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
|
||||
import org.mortbay.http.HttpContext;
|
||||
import org.mortbay.jetty.Server;
|
||||
|
||||
/**
|
||||
* This handles the starting and stopping of an eepsite tunnel and jetty
|
||||
* from a single static class so it can be called via clients.config.
|
||||
*
|
||||
* This makes installation of a new eepsite a turnkey operation -
|
||||
* the user is not required to configure a new tunnel in i2ptunnel manually.
|
||||
*
|
||||
* Usage: ZzzOTController -d $PLUGIN [start|stop]
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class ZzzOTController {
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ZzzOTController.class);
|
||||
private static Server _server;
|
||||
private static TunnelController _tunnel;
|
||||
private static ZzzOT _zzzot;
|
||||
private static Object _lock = new Object();
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length != 3 || (!"-d".equals(args[0])))
|
||||
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]");
|
||||
if ("start".equals(args[2]))
|
||||
start(args);
|
||||
else if ("stop".equals(args[2]))
|
||||
stop();
|
||||
else
|
||||
throw new IllegalArgumentException("Usage: PluginController -d $PLUGIN [start|stop]");
|
||||
}
|
||||
|
||||
public static Torrents getTorrents() {
|
||||
synchronized(_lock) {
|
||||
if (_zzzot == null)
|
||||
_zzzot = new ZzzOT();
|
||||
}
|
||||
return _zzzot.getTorrents();
|
||||
}
|
||||
|
||||
private static void start(String args[]) {
|
||||
File pluginDir = new File(args[1]);
|
||||
if (!pluginDir.exists())
|
||||
throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist");
|
||||
|
||||
// We create the private key file in advance, so that we can
|
||||
// create the help.html file from the templates
|
||||
// without waiting for i2ptunnel to create it AND build the tunnels before returning.
|
||||
Destination dest = null;
|
||||
File key = new File(pluginDir, "eepPriv.dat");
|
||||
if (!key.exists()) {
|
||||
PrivateKeyFile pkf = new PrivateKeyFile(new File(pluginDir, "eepPriv.dat"));
|
||||
try {
|
||||
dest = pkf.createIfAbsent();
|
||||
} catch (Exception e) {
|
||||
_log.error("Unable to create " + key.getAbsolutePath() + ' ' + e);
|
||||
throw new IllegalArgumentException("Unable to create " + key.getAbsolutePath() + ' ' + e);
|
||||
}
|
||||
_log.error("NOTICE: ZzzOT: New eepsite keys created in " + key.getAbsolutePath());
|
||||
_log.error("NOTICE: ZzzOT: You should back up this file!");
|
||||
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||
String b64 = dest.toBase64();
|
||||
_log.error("NOTICE: ZzzOT: Your base 32 address is " + b32);
|
||||
_log.error("NOTICE: ZzzOT: Your base 64 address is " + b64);
|
||||
}
|
||||
startJetty(pluginDir, dest);
|
||||
startI2PTunnel(pluginDir, dest);
|
||||
}
|
||||
|
||||
|
||||
private static void startI2PTunnel(File pluginDir, Destination dest) {
|
||||
File i2ptunnelConfig = new File(pluginDir, "i2ptunnel.config");
|
||||
Properties i2ptunnelProps = new Properties();
|
||||
try {
|
||||
DataHelper.loadProps(i2ptunnelProps, i2ptunnelConfig);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Cannot open " + i2ptunnelConfig.getAbsolutePath() + ' ' + ioe);
|
||||
throw new IllegalArgumentException("Cannot open " + i2ptunnelConfig.getAbsolutePath() + ' ' + ioe);
|
||||
}
|
||||
TunnelController tun = new TunnelController(i2ptunnelProps, "tunnel.0.");
|
||||
// start in foreground so we can get the destination
|
||||
//tun.startTunnelBackground();
|
||||
tun.startTunnel();
|
||||
if (dest != null) {
|
||||
List msgs = tun.clearMessages();
|
||||
for (Object s : msgs) {
|
||||
_log.error("NOTICE: ZzzOT Tunnel message: " + s);
|
||||
}
|
||||
}
|
||||
_tunnel = tun;
|
||||
}
|
||||
|
||||
private static void startJetty(File pluginDir, Destination dest) {
|
||||
if (_server != null)
|
||||
throw new IllegalArgumentException("Jetty already running!");
|
||||
migrateJettyXML(pluginDir);
|
||||
I2PAppContext context = I2PAppContext.getGlobalContext();
|
||||
File tmpdir = new File(context.getTempDir().getAbsolutePath(), "/zzzot-work");
|
||||
tmpdir.mkdir();
|
||||
File jettyXml = new File(pluginDir, "jetty.xml");
|
||||
try {
|
||||
Server serv = new Server(jettyXml.getAbsolutePath());
|
||||
HttpContext[] hcs = serv.getContexts();
|
||||
for (int i = 0; i < hcs.length; i++)
|
||||
hcs[i].setTempDirectory(tmpdir);
|
||||
serv.start();
|
||||
_server = serv;
|
||||
} catch (Throwable t) {
|
||||
_log.error("ZzzOT jetty start failed", t);
|
||||
throw new IllegalArgumentException("Jetty start failed " + t);
|
||||
}
|
||||
if (dest != null)
|
||||
launchHelp(pluginDir, dest);
|
||||
}
|
||||
|
||||
private static void stop() {
|
||||
stopI2PTunnel();
|
||||
stopJetty();
|
||||
if (_zzzot != null)
|
||||
_zzzot.stop();
|
||||
}
|
||||
|
||||
private static void stopI2PTunnel() {
|
||||
if (_tunnel == null)
|
||||
return;
|
||||
try {
|
||||
_tunnel.stopTunnel();
|
||||
} catch (Throwable t) {
|
||||
_log.error("ZzzOT tunnel stop failed", t);
|
||||
throw new IllegalArgumentException("Tunnel stop failed " + t);
|
||||
}
|
||||
_tunnel = null;
|
||||
}
|
||||
|
||||
private static void stopJetty() {
|
||||
if (_server == null)
|
||||
return;
|
||||
try {
|
||||
_server.stop();
|
||||
} catch (Throwable t) {
|
||||
_log.error("ZzzOT jetty stop failed", t);
|
||||
throw new IllegalArgumentException("Jetty stop failed " + t);
|
||||
}
|
||||
_server = null;
|
||||
}
|
||||
|
||||
/** put the directory in the jetty.xml file */
|
||||
private static void migrateJettyXML(File pluginDir) {
|
||||
File outFile = new File(pluginDir, "jetty.xml");
|
||||
if (outFile.exists())
|
||||
return;
|
||||
File fileTmpl = new File(pluginDir, "templates/jetty.xml");
|
||||
try {
|
||||
String props = FileUtil.readTextFile(fileTmpl.getAbsolutePath(), 250, true);
|
||||
if (props == null)
|
||||
throw new IOException(fileTmpl.getAbsolutePath() + " open failed");
|
||||
props = props.replace("$PLUGIN", pluginDir.getAbsolutePath());
|
||||
FileOutputStream os = new FileOutputStream(outFile);
|
||||
os.write(props.getBytes("UTF-8"));
|
||||
os.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("jetty.xml migrate failed", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/** put the directory, base32, and base64 info in the help.html file and launch a browser window to display it */
|
||||
private static void launchHelp(File pluginDir, Destination dest) {
|
||||
File fileTmpl = new File(pluginDir, "templates/help.html");
|
||||
File outFile = new File(pluginDir, "eepsite/docroot/help.html");
|
||||
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||
String b64 = dest.toBase64();
|
||||
try {
|
||||
String html = FileUtil.readTextFile(fileTmpl.getAbsolutePath(), 100, true);
|
||||
if (html == null)
|
||||
throw new IOException(fileTmpl.getAbsolutePath() + " open failed");
|
||||
html = html.replace("$PLUGIN", pluginDir.getAbsolutePath());
|
||||
html = html.replace("$B32", b32);
|
||||
html = html.replace("$B64", b64);
|
||||
FileOutputStream os = new FileOutputStream(outFile);
|
||||
os.write(html.getBytes("UTF-8"));
|
||||
os.close();
|
||||
Thread t = new I2PAppThread(new Launcher(), "ZzzOTHelp", true);
|
||||
t.start();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("ZzzOT help launch failed", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Launcher implements Runnable {
|
||||
public void run() {
|
||||
UrlLauncher.main(new String[] { "http://127.0.0.1:7662/help.html" } );
|
||||
}
|
||||
}
|
||||
}
|
36
src/jsp/WEB-INF/web.xml
Normal file
36
src/jsp/WEB-INF/web.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||
|
||||
<!-- precompiled servlets -->
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.zzzot.announce_jsp</servlet-name>
|
||||
<url-pattern>/announce.php</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.zzzot.announce_jsp</servlet-name>
|
||||
<url-pattern>/announce</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.zzzot.announce_jsp</servlet-name>
|
||||
<url-pattern>/a</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.zzzot.scrape_jsp</servlet-name>
|
||||
<url-pattern>/scrape</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.zzzot.scrape_jsp</servlet-name>
|
||||
<url-pattern>/scrape.php</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
200
src/jsp/announce.jsp
Normal file
200
src/jsp/announce.jsp
Normal file
@ -0,0 +1,200 @@
|
||||
<%@page import="java.util.ArrayList" %><%@page import="java.util.Collections" %><%@page import="java.util.List" %><%@page import="java.util.Map" %><%@page import="java.util.HashMap" %><%@page import="net.i2p.data.Base64" %><%@page import="net.i2p.data.Destination" %><%@page import="net.i2p.zzzot.*" %><%@page import="org.klomp.snark.bencode.BEncoder" %><%
|
||||
|
||||
/*
|
||||
* Above one-liner is so there is no whitespace -> IllegalStateException
|
||||
*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* USE CAUTION WHEN EDITING
|
||||
* Trailing whitespace OR NEWLINE on the last line will cause
|
||||
* IllegalStateExceptions !!!
|
||||
*
|
||||
*/
|
||||
// would be nice to make these configurable
|
||||
final int MAX_RESPONSES = 25;
|
||||
final int INTERVAL = 27*60;
|
||||
|
||||
// so the chars will turn into bytes correctly
|
||||
request.setCharacterEncoding("ISO-8859-1");
|
||||
java.io.OutputStream cout = response.getOutputStream();
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
response.setContentType("text/plain");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
String info_hash = request.getParameter("info_hash");
|
||||
String peer_id = request.getParameter("peer_id");
|
||||
// ignored
|
||||
String port = request.getParameter("port");
|
||||
// ignored
|
||||
String uploaded = request.getParameter("uploaded");
|
||||
// ignored
|
||||
String downloaded = request.getParameter("downloaded");
|
||||
String sleft = request.getParameter("left");
|
||||
String event = request.getParameter("event");
|
||||
String ip = request.getParameter("ip");
|
||||
String numwant = request.getParameter("numwant");
|
||||
// ignored, use someday to enforce destination
|
||||
String him = request.getHeader("X-I2P-DestB32");
|
||||
String xff = request.getHeader("X-Forwarded-For");
|
||||
|
||||
boolean fail = false;
|
||||
String msg = "bad announce";
|
||||
|
||||
if (xff != null) {
|
||||
fail = true;
|
||||
msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
}
|
||||
|
||||
if (info_hash == null && !fail) {
|
||||
fail = true;
|
||||
msg = "no info hash";
|
||||
}
|
||||
|
||||
if (ip == null && !fail) {
|
||||
fail = true;
|
||||
msg = "no ip (dest)";
|
||||
}
|
||||
|
||||
if (peer_id == null && !fail) {
|
||||
fail = true;
|
||||
msg = "no peer id";
|
||||
}
|
||||
|
||||
InfoHash ih = null;
|
||||
if (!fail) {
|
||||
try {
|
||||
ih = new InfoHash(info_hash);
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad infohash " + e;
|
||||
}
|
||||
}
|
||||
|
||||
Destination d = null;
|
||||
if (!fail) {
|
||||
try {
|
||||
if (ip.endsWith(".i2p"))
|
||||
ip = ip.substring(0, ip.length() - 4);
|
||||
d = new Destination(ip); // from b64 string
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad dest " + e;
|
||||
}
|
||||
}
|
||||
|
||||
PID pid = null;
|
||||
if (!fail) {
|
||||
try {
|
||||
pid = new PID(peer_id);
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad peer id " + e;
|
||||
}
|
||||
}
|
||||
|
||||
// int params
|
||||
|
||||
// ignored
|
||||
long up = 0;
|
||||
try {
|
||||
up = Long.parseLong(uploaded);
|
||||
if (up < 0)
|
||||
up = 0;
|
||||
} catch (NumberFormatException nfe) {};
|
||||
|
||||
// ignored
|
||||
long down = 0;
|
||||
try {
|
||||
down = Long.parseLong(downloaded);
|
||||
if (down < 0)
|
||||
down = 0;
|
||||
} catch (NumberFormatException nfe) {};
|
||||
|
||||
int want = MAX_RESPONSES;
|
||||
try {
|
||||
want = Integer.parseInt(numwant);
|
||||
if (want > MAX_RESPONSES)
|
||||
want = MAX_RESPONSES;
|
||||
else if (want < 0)
|
||||
want = 0;
|
||||
} catch (NumberFormatException nfe) {};
|
||||
|
||||
long left = 0;
|
||||
if (!"completed".equals(event)) {
|
||||
try {
|
||||
left = Long.parseLong(sleft);
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
} catch (NumberFormatException nfe) {};
|
||||
}
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
Map<String, Object> m = new HashMap();
|
||||
if (fail) {
|
||||
m.put("failure reason", msg);
|
||||
} else if ("stopped".equals(event)) {
|
||||
Peers peers = torrents.get(ih);
|
||||
if (peers != null)
|
||||
peers.remove(pid);
|
||||
m.put("interval", Integer.valueOf(INTERVAL));
|
||||
} else {
|
||||
Peers peers = torrents.get(ih);
|
||||
if (peers == null) {
|
||||
peers = new Peers();
|
||||
Peers p2 = torrents.putIfAbsent(ih, peers);
|
||||
if (p2 != null)
|
||||
peers = p2;
|
||||
}
|
||||
|
||||
// fixme same peer id, different dest
|
||||
Peer p = peers.get(pid);
|
||||
if (p == null) {
|
||||
p = new Peer(pid.getData(), d);
|
||||
Peer p2 = peers.putIfAbsent(pid, p);
|
||||
if (p2 != null)
|
||||
p = p2;
|
||||
}
|
||||
p.setLeft(left);
|
||||
|
||||
m.put("interval", Integer.valueOf(INTERVAL));
|
||||
int size = peers.size();
|
||||
int seeds = peers.countSeeds();
|
||||
m.put("complete", Integer.valueOf(seeds));
|
||||
m.put("incomplete", Integer.valueOf(size - seeds));
|
||||
if (want <= 0) {
|
||||
// snark < 0.7.13 always wants a list
|
||||
m.put("peers", java.util.Collections.EMPTY_LIST);
|
||||
} else {
|
||||
List<Peer> peerlist = new ArrayList(peers.values());
|
||||
peerlist.remove(p); // them
|
||||
if (want < size - 1) {
|
||||
Collections.shuffle(peerlist);
|
||||
m.put("peers", peerlist.subList(0, want));
|
||||
} else {
|
||||
m.put("peers", peerlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
BEncoder.bencode(m, cout);
|
||||
|
||||
/*
|
||||
* Remove the newline on the last line or
|
||||
* it will generate an IllegalStateException
|
||||
*
|
||||
*/
|
||||
%>
|
10
src/jsp/index.html
Normal file
10
src/jsp/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0;url=index.jsp" />
|
||||
<title>zzzot</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="index.jsp">Enter</a>
|
||||
</body>
|
||||
</html>
|
||||
|
14
src/jsp/index.jsp
Normal file
14
src/jsp/index.jsp
Normal file
@ -0,0 +1,14 @@
|
||||
<%@page import="net.i2p.zzzot.ZzzOTController" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>ZzzOT</title>
|
||||
</head><body style="background-color: #000; color: #c30; font-size: 400%;">
|
||||
<p>
|
||||
zzzot
|
||||
<p>
|
||||
<table cellspacing="8">
|
||||
<tr><td>Torrents:<td align="right"><%=ZzzOTController.getTorrents().size()%>
|
||||
<tr><td>Peers:<td align="right"><%=ZzzOTController.getTorrents().countPeers()%>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
92
src/jsp/scrape.jsp
Normal file
92
src/jsp/scrape.jsp
Normal file
@ -0,0 +1,92 @@
|
||||
<%@page import="java.util.ArrayList" %><%@page import="java.util.List" %><%@page import="java.util.Map" %><%@page import="java.util.HashMap" %><%@page import="net.i2p.zzzot.*" %><%@page import="org.klomp.snark.bencode.BEncoder" %><%
|
||||
|
||||
/*
|
||||
* Above one-liner is so there is no whitespace -> IllegalStateException
|
||||
*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* USE CAUTION WHEN EDITING
|
||||
* Trailing whitespace OR NEWLINE on the last line will cause
|
||||
* IllegalStateExceptions !!!
|
||||
*
|
||||
*/
|
||||
// so the chars will turn into bytes correctly
|
||||
request.setCharacterEncoding("ISO-8859-1");
|
||||
java.io.OutputStream cout = response.getOutputStream();
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
response.setContentType("text/plain");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
String info_hash = request.getParameter("info_hash");
|
||||
String xff = request.getHeader("X-Forwarded-For");
|
||||
|
||||
boolean fail = false;
|
||||
String msg = "bad";
|
||||
|
||||
if (xff != null) {
|
||||
fail = true;
|
||||
msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
}
|
||||
|
||||
boolean all = info_hash == null;
|
||||
|
||||
InfoHash ih = null;
|
||||
if ((!all) && !fail) {
|
||||
try {
|
||||
ih = new InfoHash(info_hash);
|
||||
} catch (Exception e) {
|
||||
fail = true;
|
||||
msg = "bad infohash " + e;
|
||||
}
|
||||
}
|
||||
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
|
||||
// build 3-level dictionary
|
||||
Map<String, Object> m = new HashMap();
|
||||
if (fail) {
|
||||
m.put("failure reason", msg);
|
||||
} else {
|
||||
List<InfoHash> ihList = new ArrayList();
|
||||
if (all)
|
||||
ihList.addAll(torrents.keySet());
|
||||
else
|
||||
ihList.add(ih);
|
||||
Map<String, Map> files = new HashMap();
|
||||
for (InfoHash ihash : ihList) {
|
||||
Peers peers = torrents.get(ihash);
|
||||
if (peers == null)
|
||||
continue;
|
||||
Map<String, Object> dict = new HashMap();
|
||||
int size = peers.size();
|
||||
int seeds = peers.countSeeds();
|
||||
dict.put("complete", Integer.valueOf(seeds));
|
||||
dict.put("incomplete", Integer.valueOf(size - seeds));
|
||||
dict.put("downloaded", Integer.valueOf(0));
|
||||
files.put(new String(ihash.getData(), "ISO-8859-1"), dict);
|
||||
}
|
||||
m.put("files", files);
|
||||
}
|
||||
BEncoder.bencode(m, cout);
|
||||
|
||||
/*
|
||||
* Remove the newline on the last line or
|
||||
* it will generate an IllegalStateException
|
||||
*
|
||||
*/
|
||||
%>
|
74
src/jsp/seedless.jsp
Normal file
74
src/jsp/seedless.jsp
Normal file
@ -0,0 +1,74 @@
|
||||
<%@page import="net.i2p.crypto.SHA256Generator" %><%@page import="net.i2p.data.Base32" %><%@page import="net.i2p.data.Base64" %><%@page import="net.i2p.zzzot.*" %><%
|
||||
|
||||
/*
|
||||
* Copyright 2010 zzz (zzz@mail.i2p)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
String req = request.getHeader("X-Seedless");
|
||||
String me = request.getHeader("Host");
|
||||
// unused, we don't accept announces
|
||||
String him = request.getHeader("X-I2P-DestB32");
|
||||
String xff = request.getHeader("X-Forwarded-For");
|
||||
|
||||
response.setContentType("text/plain");
|
||||
response.setHeader("X-Seedless", me);
|
||||
|
||||
final int US_MINUTES = 360;
|
||||
final int PEER_MINUTES = 60;
|
||||
|
||||
if (xff != null) {
|
||||
String msg = "Non-I2P access denied";
|
||||
response.setStatus(403, msg);
|
||||
out.println(msg);
|
||||
} else if (req == null) {
|
||||
out.println("seedless server");
|
||||
} else if (req.startsWith("announce ")) {
|
||||
out.println("");
|
||||
} else if (req.startsWith("locate ") && me != null) {
|
||||
// ignore the search string, if any, in the request
|
||||
// us
|
||||
out.println(Base64.encode(me + ' ' + US_MINUTES + " bt-tracker"));
|
||||
// all the peers
|
||||
Torrents torrents = ZzzOTController.getTorrents();
|
||||
for (InfoHash ihash : torrents.keySet()) {
|
||||
Peers peers = torrents.get(ihash);
|
||||
if (peers == null)
|
||||
continue;
|
||||
for (Peer p : peers.values()) {
|
||||
// dest to b32
|
||||
String ip = (String) p.get("ip");
|
||||
if (ip.endsWith(".i2p"))
|
||||
ip = ip.substring(0, ip.length() - 4);
|
||||
String b32 = Base32.encode(SHA256Generator.getInstance().calculateHash(Base64.decode(ip)).getData()) + ".b32.i2p ";
|
||||
// service type
|
||||
String role;
|
||||
if (p.isSeed())
|
||||
role = " bt-seed";
|
||||
else
|
||||
role = " bt-leech";
|
||||
// spg wants UTF-8 but all we have is binary data, sorry
|
||||
String ihs = new String(ihash.getData(), "ISO-8859-1");
|
||||
String ids = new String((byte[])p.get("peer id"), "ISO-8859-1");
|
||||
out.println(Base64.encode(b32 + PEER_MINUTES + role +
|
||||
" info_hash=" + ihs +
|
||||
" peer_id=" + ids));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.println("2");
|
||||
}
|
||||
|
||||
%>
|
Reference in New Issue
Block a user