From 32baafb1fde2194a1ef7a658a37c8b1ff4d8f4cd Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 9 Jan 2022 12:12:58 -0500 Subject: [PATCH] Start of a plugin version WIP --- build.xml | 65 ++++++++ plugin-src/build.xml | 44 ++++++ .../src/net/i2p/itoopie/plugin/Itoopie.java | 108 +++++++++++++ plugin/clients.config | 5 + scripts/itoopie.conf | 3 + scripts/makeplugin.sh | 147 ++++++++++++++++++ scripts/plugin.config | 8 + src/net/i2p/itoopie/gui/TrayManager.java | 17 +- 8 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 plugin-src/build.xml create mode 100644 plugin-src/src/net/i2p/itoopie/plugin/Itoopie.java create mode 100644 plugin/clients.config create mode 100644 scripts/itoopie.conf create mode 100755 scripts/makeplugin.sh create mode 100644 scripts/plugin.config diff --git a/build.xml b/build.xml index 403e90c6a..346c55ce0 100644 --- a/build.xml +++ b/build.xml @@ -32,6 +32,15 @@ + + + + + + + + + @@ -190,4 +199,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin-src/build.xml b/plugin-src/build.xml new file mode 100644 index 000000000..c72c6f403 --- /dev/null +++ b/plugin-src/build.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin-src/src/net/i2p/itoopie/plugin/Itoopie.java b/plugin-src/src/net/i2p/itoopie/plugin/Itoopie.java new file mode 100644 index 000000000..4b183138a --- /dev/null +++ b/plugin-src/src/net/i2p/itoopie/plugin/Itoopie.java @@ -0,0 +1,108 @@ +package net.i2p.itoopie.plugin; +/* + * 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 javax.swing.UIManager; + +import net.i2p.I2PAppContext; +import net.i2p.app.*; +import static net.i2p.app.ClientAppState.*; +import net.i2p.util.Log; + +import net.i2p.itoopie.gui.GUIHelper; +import net.i2p.itoopie.gui.TrayManager; +import net.i2p.itoopie.gui.WindowHandler; + +/** + * + * @author zzz + */ +public class Itoopie implements ClientApp { + private final I2PAppContext _context; + private final Log _log; + private final ClientAppManager _mgr; + private TrayManager trayManager; + private ClientAppState _state = UNINITIALIZED; + + public Itoopie(I2PAppContext ctx, ClientAppManager mgr, String args[]) { + _context = ctx; + _log = ctx.logManager().getLog(Itoopie.class); + _mgr = mgr; + _state = INITIALIZED; + } + + /** + * Not supported + */ + public synchronized static void main(String args[]) { + throw new UnsupportedOperationException("Must use ClientApp interface"); + } + + /////// ClientApp methods + + public synchronized void startup() throws Exception { + if (_state != STOPPED && _state != INITIALIZED && _state != START_FAILED) { + _log.error("Start while state = " + _state); + return; + } + trayManager = TrayManager.getInstance(); + trayManager.startManager(); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + GUIHelper.setDefaultStyle(); + } catch (Exception ex) {} + // Popup Main window. + WindowHandler.toggleFrames(); + changeState(RUNNING); + } + + public synchronized void shutdown(String[] args) { + if (_state == STOPPED) + return; + changeState(STOPPING); + trayManager.stopManager(); + // TODO stop it + trayManager = null; + changeState(STOPPED); + } + + public ClientAppState getState() { + return _state; + } + + public String getName() { + return "itoopie"; + } + + public String getDisplayName() { + return "Itoopie"; + } + + /////// end ClientApp methods + + private synchronized void changeState(ClientAppState state) { + if (state == _state) + return; + _state = state; + _mgr.notify(this, state, null, null); + } + + private synchronized void changeState(ClientAppState state, String msg, Exception e) { + if (state == _state) + return; + _state = state; + _mgr.notify(this, state, msg, e); + } +} diff --git a/plugin/clients.config b/plugin/clients.config new file mode 100644 index 000000000..bf23ced54 --- /dev/null +++ b/plugin/clients.config @@ -0,0 +1,5 @@ +clientApp.0.main=net.i2p.itoopie.plugin.Itoopie +clientApp.0.name=itoopie +clientApp.0.delay=0 +clientApp.0.startOnLoad=true +clientApp.0.classpath=$PLUGIN/lib/itoopie-plugin.jar,$PLUGIN/lib/itoopie.jar,$PLUGIN/lib/commons-logging.jar,$PLUGIN/lib/jchart2d.jar,$PLUGIN/lib/json-smart.jar,$PLUGIN/lib/xmlgraphics-commons.jar diff --git a/scripts/itoopie.conf b/scripts/itoopie.conf new file mode 100644 index 000000000..0e49fe591 --- /dev/null +++ b/scripts/itoopie.conf @@ -0,0 +1,3 @@ +server.hostname=localhost +server.password=itoopie +server.port=7657 diff --git a/scripts/makeplugin.sh b/scripts/makeplugin.sh new file mode 100755 index 000000000..ed055a608 --- /dev/null +++ b/scripts/makeplugin.sh @@ -0,0 +1,147 @@ +#!/bin/sh +# +# basic packaging up of a plugin +# +# usage: makeplugin.sh plugindir +# +# zzz 2010-02 +# zzz 2014-08 added support for su3 files +# + +if [ -z "$I2P" -a -d "$PWD/../i2p.i2p/pkg-temp" ]; then + export I2P=../i2p.i2p/pkg-temp +fi + +if [ ! -d "$I2P" ]; then + echo "Can't locate your I2P installation. Please add a environment variable named I2P with the path to the folder as value" + echo "On OSX this solved with running: export I2P=/Applications/i2p if default install directory is used." + exit 1 +fi + +PUBKEYDIR=$HOME/.i2p-plugin-keys +PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key +PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key +B64KEYFILE=$PUBKEYDIR/plugin-public-signing.txt +PUBKEYSTORE=$PUBKEYDIR/plugin-su3-public-signing.crt +PRIVKEYSTORE=$PUBKEYDIR/plugin-su3-keystore.ks +KEYTYPE=RSA_SHA512_4096 + +PLUGINDIR=${1:-plugin} + +PC=plugin.config +PCT=${PC}.tmp + +if [ ! -d $PLUGINDIR ] +then + echo "You must have a $PLUGINDIR directory" + exit 1 +fi + +if [ ! -f $PLUGINDIR/$PC ] +then + echo "You must have a $PLUGINDIR/$PC file" + exit 1 +fi + +SIGNER=`grep '^signer=' $PLUGINDIR/$PC` +if [ "$?" -ne "0" ] +then + echo "You must have a plugin name in $PC" + echo 'For example name=foo' + exit 1 +fi +SIGNER=`echo $SIGNER | cut -f 2 -d '='` + +if [ ! -f $PRIVKEYFILE ] +then + echo "Creating new XPI2P DSA keys" + mkdir -p $PUBKEYDIR || exit 1 + 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 XPI2P keys: $PUBKEYFILE $PRIVKEYFILE" +fi + +if [ ! -f $PRIVKEYSTORE ] +then + echo "Creating new SU3 $KEYTYPE keys for $SIGNER" + java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File keygen -t $KEYTYPE $PUBKEYSTORE $PRIVKEYSTORE $SIGNER || exit 1 + echo '*** Save your password in a safe place!!! ***' + rm -rf logs/ + # copy to the router dir so verify will work + CDIR=$I2P/certificates/plugin + mkdir -p $CDIR || exit 1 + CFILE=$CDIR/`echo $SIGNER | sed s/@/_at_/`.crt + cp $PUBKEYSTORE $CFILE + chmod 444 $PUBKEYSTORE + chmod 400 $PRIVKEYSTORE + chmod 644 $CFILE + echo "Created new SU3 keys: $PUBKEYSTORE $PRIVKEYSTORE" + echo "Copied public key to $CFILE for testing" +fi + +rm -f plugin.zip + +OPWD=$PWD +cd $PLUGINDIR + +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 || exit 1 + +# add our Base64 key +grep -v '^key=' $PC > $PCT +B64KEY=`cat $B64KEYFILE` +echo "key=$B64KEY" >> $PCT || exit 1 +mv $PCT $PC || exit 1 + +# zip it +zip -r $OPWD/plugin.zip * || 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 +SU3=${NAME}.su3 +cd $OPWD + +# sign it +echo 'Signing. ...' +java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign plugin.zip $XPI2P $PRIVKEYFILE $VERSION || exit 1 +java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File sign -c PLUGIN -t $KEYTYPE plugin.zip $SU3 $PRIVKEYSTORE $VERSION $SIGNER || 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 +java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File showversion $SU3 || exit 1 +java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File verifysig -k $PUBKEYSTORE $SU3 || exit 1 +rm -rf logs/ + +echo 'Plugin files created: ' +wc -c $XPI2P +wc -c $SU3 + +exit 0 diff --git a/scripts/plugin.config b/scripts/plugin.config new file mode 100644 index 000000000..5e2af31c0 --- /dev/null +++ b/scripts/plugin.config @@ -0,0 +1,8 @@ +name=itoopie +signer=zzz-plugin@mail.i2p +description=Router Control +author=zzz +updateURL.su3=http://stats.i2p/i2p/plugins/itoopie-update.su3 +websiteURL=http://zzz.i2p/forums/16 +license=Apache 2.0 +min-i2p-version=0.9.11 diff --git a/src/net/i2p/itoopie/gui/TrayManager.java b/src/net/i2p/itoopie/gui/TrayManager.java index 2670407fb..62c0c8312 100644 --- a/src/net/i2p/itoopie/gui/TrayManager.java +++ b/src/net/i2p/itoopie/gui/TrayManager.java @@ -50,7 +50,7 @@ public class TrayManager { /** * Add the tray icon to the system tray and start everything up. */ - public void startManager() { + public synchronized void startManager() { SwingUtilities.invokeLater(new Runnable(){ public void run(){ if(SystemTray.isSupported()) { @@ -71,7 +71,20 @@ public class TrayManager { } }); } - + + /** + * @since 0.0.5 for plugin only + */ + public synchronized void stopManager() { + try { + if (trayIcon != null && SystemTray.isSupported()) { + SystemTray.getSystemTray().remove(trayIcon); + // TODO stop it + trayIcon = null; + } + } catch (Exception e) {} + } + protected void languageChanged() { trayIcon.setPopupMenu(getMainMenu()); }