Compare commits

..

965 Commits

Author SHA1 Message Date
zzz
16d2bdc1db 0.9.40 2019-05-07 11:54:18 +00:00
zzz
edb352b9d0 replace news cert 2019-05-07 11:44:11 +00:00
zzz
ffbf3d2023 javadocs after review 2019-05-07 11:42:31 +00:00
zzz
0147f003c4 Star icons update 2019-05-03 13:20:50 +00:00
zzz
50d93b1993 regenerate tr man pages 2019-05-03 12:57:12 +00:00
zzz
a39549a3d9 pull translations from transifex 2019-05-03 12:53:03 +00:00
meeh
9adabadeb9 Mac OSX Launcher: shell script for downloading and building Sparkle. 2019-05-02 23:12:54 +00:00
meeh
61303bfd0b Mac OSX Launcher: The podfile, which describes which 3rdparty libraries to pull at compile time. 2019-05-02 23:01:32 +00:00
meeh
e45963dbcb Mac OSX Launcher: main.mm updated to use the new swift main class name. 2019-05-02 23:00:44 +00:00
meeh
5f689ccbd4 Mac OSX Launcher: project file, workspace file and entittlements file updates. 2019-05-02 23:00:02 +00:00
meeh
17bb36deee Mac OSX Launcher: Info.plist update, adding Sparkle pubkey. 2019-05-02 22:59:01 +00:00
meeh
0b50c36c8a Mac OSX Launcher: xib UI updates. 2019-05-02 22:56:53 +00:00
meeh
feaa82181f Mac OSX Launcher: Router / Java wrapper. 2019-05-02 22:55:55 +00:00
meeh
803447b4c3 Mac OSX Launcher: Swift - ObjC/C++ bridge header update. 2019-05-02 22:55:04 +00:00
meeh
e93fb5c084 Mac OSX Launcher: Reduce amount of compiler warnings under build. 2019-05-02 22:54:02 +00:00
meeh
6a418ebcab Mac OSX Launcher: Swift 4.2 update in subprocess class. 2019-05-02 22:53:00 +00:00
meeh
67ca6e6552 Mac OSX Launcher: Identifiers file to hold Bundle ID and other static domain data. 2019-05-02 22:52:16 +00:00
meeh
540e7c37e0 Mac OSX Launcher: Cleanup and update in UI classes. Swift 4.2 2019-05-02 22:51:35 +00:00
meeh
7cb0c9bbb4 Mac OSX Launcher: Router management/healthcheck code updates. 2019-05-02 22:50:55 +00:00
meeh
66deb5dc7e Mac OSX Launcher: Cleaned, updated and renamed main swift class. 2019-05-02 22:50:12 +00:00
meeh
3e10745717 Mac OSX Launcher: Storyboard and NIB updates. Also moved to resources which they belong. 2019-05-02 22:48:16 +00:00
meeh
84419bbf0b Mac OSX Launcher: Common code for browser communication/control. 2019-05-02 22:47:01 +00:00
meeh
d81f993f81 Mac OSX Launcher: (feature disabled, WIP) new pretty userinterface. 2019-05-02 22:45:41 +00:00
meeh
8453c5cce0 merge of '4347aa09448af24e7796c3282763d4a1bfc5c07f'
and '648083ff7dde91e5aa4416e1a9f85989acca9fb6'
2019-05-02 22:43:41 +00:00
meeh
b2b047b4aa Mac OSX Launcher: Licenses for frameworks/libraries pulled from cocoapods under compile time. 2019-05-02 22:43:34 +00:00
meeh
7aa68c0a2b merge of '884fdac5153dc99fad97b61b1ef1172d8f0c09a9'
and 'c88b4076c5928a0e87d073abc0c0c94a341c921e'
2019-05-02 22:41:50 +00:00
meeh
811d1ccf9d Mac OSX Launcher: Moving utils classes to common directory between sub-projects + Swift 4.2 update. 2019-05-02 22:41:25 +00:00
meeh
2af1f68d84 Mac OSX Launcher: Misc metadata updates for the StartupItemApp sub-bundle. 2019-05-02 22:40:18 +00:00
meeh
56eb11bc17 Mac OSX Launcher: Adding Swift 4.2 support to the preferences UI classes. 2019-05-02 22:39:11 +00:00
meeh
214efb8ef9 Mac OSX Launcher: Moved Objective-C & C++ files to a better location. 2019-05-02 19:30:56 +00:00
meeh
d1631643a5 Mac OSX Launcher: Misc updates related to router management. 2019-05-02 19:26:52 +00:00
meeh
315d7728d8 Mac OSX Launcher: Sparkle License 2019-05-02 19:10:19 +00:00
meeh
647f9e728f merge of '89268c439b2c0098fe4dd039cb032f5c5717a2e5'
and 'de08714d459702cd7ba8c86570c747dca157ed26'
2019-05-02 16:16:16 +00:00
meeh
fa2897d2f8 Mac OSX Launcher: Delay extension for the DispatchQueue Cocoa/OSX class. 2019-05-02 16:16:11 +00:00
meeh
539f880f9b merge of '4ae3e891f8510b146feae122bacc862468db060e'
and '666d27bab7047baeaa2c753159098eda75635c5e'
2019-05-02 16:14:46 +00:00
meeh
9caa7a61b0 Mac OSX Launcher: EditorTableView for the 2019 redesign/UI improvements. 2019-05-02 16:14:38 +00:00
zzz
52b14142bb Android: Catch ISE from PRNG at shutdown (ticket #2077) 2019-05-02 14:59:16 +00:00
zzz
7f60ee9f8b Console: NTCP2 check 2019-05-02 14:25:43 +00:00
zzz
b9726a0af8 UPnP: Remove finalize() in HTTPSocket (ticket #2490) 2019-05-02 14:08:25 +00:00
zzz
bb86c56e77 NTCP: Tweak previous fix to prevent leak (ticket #2476) 2019-05-02 12:25:18 +00:00
zzz
8cdeff74c7 GeoIP Maxmind 2019-04-29 2019-05-02 12:17:59 +00:00
zzz
acf5c314de NTCP: Rare EventPumper 100% CPU fix (ticket #2476) 2019-05-02 11:55:04 +00:00
zzz
20413f00c0 Build: Fix installers broken by removal of apparmor file 2019-04-28 14:44:28 +00:00
zzz
aa551acec4 Console: Remove metadata from new icons 2019-04-27 12:17:08 +00:00
zzz
f088ea1263 Build: Fix Precise build 2019-04-26 12:33:15 +00:00
zzz
46e31746b4 Build: Drop unmaintained sample apparmor script (ticket #2319)
We support apparmor for Debian package installs only.
2019-04-25 16:35:19 +00:00
zzz
981737f8ed i2ptunnel: Force connect delay and bulk profile for most
client tunnel types, and hide from UI
Reduce delay
Set IRC to bulk
2019-04-25 16:16:32 +00:00
str4d
5f01796bae Travis CI: Run tests against OpenJDK 12 2019-04-25 15:36:07 +00:00
zzz
b2575643a8 Transport: Disable NTCP 1 by default 2019-04-25 13:29:14 +00:00
zzz
baeaa65829 update po source for tx 2019-04-24 14:25:43 +00:00
zzz
5afa32a393 Crypto: Catch ProviderException in KeyStoreUtil (ticket #2479) 2019-04-24 12:23:35 +00:00
zzz
ca0f12782b New backup news server 2019-04-23 18:33:57 +00:00
zzz
148ed1e3a0 rh.bat fix 2019-04-23 17:25:44 +00:00
zzz
6f86522c2b Build: Add script to edit windows installer resources 2019-04-23 16:26:17 +00:00
zzz
5db67f13e1 Util: Dump system properties in SystemVersion 2019-04-23 13:24:03 +00:00
zzz
21504f1539 Build:
- Switch to IzPack 5.1.3 for building releases (ticket #1864)
 - Use izpack2exe for Windows installer (ticket #2403)
2019-04-22 18:01:47 +00:00
str4d
fd311c7e1a Gradle: Fix getBuiltBy() to work when override.properties does not exist 2019-04-21 22:31:45 +00:00
str4d
7c71ff106b Tests: Fix ministreaming tests after access filtering changes 2019-04-21 22:27:00 +00:00
str4d
d13bf0b72a Gradle: Use tested version of Mockito
The Ant JUnit tests have been tested previously with 2.5.0 as working.
2.11.0 is causing issues that are manifesting as Gradle-specific test
failures. We can upgrade this explicitly when we also upgrade the
dependency in the Ant-based CI system.
2019-04-21 22:08:34 +00:00
str4d
9e0934f958 Build: Fix titles in ministreaming and streaming JAR manifests 2019-04-21 21:03:39 +00:00
str4d
1cc330ba66 Gradle: Generate attributes for JAR manifests 2019-04-21 21:01:28 +00:00
str4d
967dde4395 Gradle: Generate reproducible archives 2019-04-21 18:09:20 +00:00
str4d
278870606b Gradle: Fix deprecations 2019-04-21 16:38:09 +00:00
str4d
e70a2c765b Update Jetty and Tomcat versions in Gradle build scripts 2019-04-21 16:37:28 +00:00
zzz
31856e8895 Router: Update NTCP checks for NTCP2
Remove old check for 0.6.1.32 and earlier routers
2019-04-20 18:36:43 +00:00
zzz
22aefa2042 Console, SusiDNS: New icons from Sadie
Source: https://github.com/feathericons/feather
Feather is licensed under the MIT License.
https://raw.githubusercontent.com/feathericons/feather/master/LICENSE
All icons converted from SVG to PNG, brightness adjusted, colourized with #848484 and resized
Some are combined and modified
2019-04-20 14:23:52 +00:00
zab2
aeded8c495 Add the blue outproxy to the default proxy list 2019-04-20 08:34:08 +00:00
zzz
3248a15d59 Debian: Update Bionic/Cosmic to include patch for Jetty 9.4 2019-04-19 13:55:38 +00:00
zzz
5c81c00a18 Utils: CoDel minor speedup (ticket #2398) 2019-04-18 13:53:27 +00:00
zzz
ea7ddaf6d5 Console: Improve error message when graphs disabled (ticket #2452) 2019-04-18 13:17:45 +00:00
zzz
a8ad30b335 PeerManager API cleanup (ticket #2456) 2019-04-18 12:46:51 +00:00
zzz
67570db664 Transport: More fixes for NTCP when SSU disabled (ticket #1417) 2019-04-17 17:45:49 +00:00
zzz
87d8d69a20 Console: New icons from Sadie
Source: https://github.com/feathericons/feather
Feather is licensed under the MIT License.
https://raw.githubusercontent.com/feathericons/feather/master/LICENSE
All icons converted from SVG to PNG, brightness adjusted, colourized with #848484 and resized
Some are combined and modified
2019-04-16 11:10:29 +00:00
zab2
e967b26f5a update javadoc 2019-04-16 02:30:56 +00:00
zab2
e5540d051f proper fix for memory bug 2019-04-16 00:37:29 +00:00
zab2
7ce81db9a8 forget the known destinations when reloading 2019-04-15 23:40:02 +00:00
zzz
e42e04c0f0 Console: Don't display I2CP error during soft restart (ticket #2468) 2019-04-15 12:49:07 +00:00
zzz
d32d5b5f29 NamingService: Fix class selection in app context (ticket #2469) 2019-04-15 12:34:41 +00:00
zzz
8d00774b5e Tomcat 8.5.40 2019-04-15 11:45:52 +00:00
zab2
89b38f4fff add my certificate for plugins 2019-04-13 19:41:40 +00:00
zzz
0dbc809111 i2ptunnel: Fix saving encrypted LS config
Disable registration authentication when encrypted
2019-04-13 19:02:35 +00:00
zzz
64c7625524 i2ptunnel: Hide blinded-with-password config 2019-04-12 12:08:09 +00:00
zzz
071e702e56 i2ptunnel: Hide I2CP config in router context 2019-04-11 20:16:44 +00:00
zzz
363317fc26 i2ptunnel: Disallow any encrypted LS for offline keys 2019-04-11 15:59:11 +00:00
zzz
f4d7a6d0d4 i2ptunnel: Disallow encrypted LS for offline keys 2019-04-11 15:38:03 +00:00
zzz
b5a4f1626f whitespace 2019-04-11 15:13:58 +00:00
zzz
73790e2353 i2ptunnel: Fix NPE creating server tunnel
Add Red25519 sigtype option for servers
Fix if clause in editClient
2019-04-11 14:33:38 +00:00
zzz
dd5f8b45ef i2ptunnel: jsp whitespace removal 2019-04-11 14:00:42 +00:00
zzz
2960156b33 Blinding: Missed PKF file from last checkin
Add to CLI
2019-04-11 11:44:57 +00:00
zzz
9a72c4b2d1 encrypt mode checks 2019-04-10 19:56:59 +00:00
zzz
7d4acb62d0 i2ptunnel: Display encrypted b32
Blinding: Allow secret flag without attached secret
2019-04-10 19:52:03 +00:00
zzz
cddace2a1d log tweak 2019-04-10 18:31:24 +00:00
zzz
859584c2b3 NTCP2: Allow longer padding in msg 1 if NTCP1 disabled 2019-04-10 18:28:51 +00:00
zzz
6237fc89ad Jetty: Hide sizes and dates of directories in listings 2019-04-10 18:25:20 +00:00
zzz
cde53537af i2ptunnel: Config UI for encrypted ls2 2019-04-08 20:37:58 +00:00
zzz
5490de1d61 Router: Replace GarlicConfig setters with constructor args 2019-04-08 16:12:14 +00:00
zab2
488e89a0b4 merge of '42afa0510b2e7c8b0db05507c44b689084606ba9'
and '8109f9041b31355f5e1f788378f43f20a4ef22b3'
2019-04-08 15:46:40 +00:00
zab2
4774cf6c37 Order recorded destinations pt2 2019-04-08 15:46:23 +00:00
zzz
7c7b0cb7fd Util: Fix memory leak in compressor (ticket #2471) 2019-04-08 15:37:20 +00:00
zab2
6aeb89ccd0 Order recorded destinations 2019-04-08 08:48:40 +00:00
zzz
6cc39a2672 Build: Fix up javadoc targets in sub-build.xml files for maven central 2019-04-07 18:09:04 +00:00
zab2
cca68f9b79 bump -4 for acces filter fix 2019-04-06 15:35:31 +00:00
zab2
904bf2a90b Only inspect the last threshold.seconds when determining if there is a breach. Otherwise older breaches would be counted as current 2019-04-06 15:35:20 +00:00
zab2
8a001adf59 Move all disk i/o to a single thread to prevent very rare errors when running multiple tunnels 2019-04-06 15:25:37 +00:00
zab2
2c602fa46b access list cannot be defined from ui 2019-04-05 18:20:59 +00:00
zab2
1c90985f93 recorder -> record 2019-04-04 09:29:54 +00:00
zab2
3498ab05f4 define thresholds in seconds, not minutes 2019-04-04 07:31:54 +00:00
zab2
d809b592c9 display filter definition parsing errors in the UI message box 2019-04-03 15:14:39 +00:00
zzz
c3aa459872 merge of 'cbd8a21f0033ee2af8c73bd2a312059869142c83'
and 'debf8ccdb50ef7789027ba5588aa534a1195f3a9'
2019-04-03 13:27:35 +00:00
zzz
d389b3b57c I2PTunnel: Start/stop POST throttle timer 2019-04-03 13:21:41 +00:00
zab2
76ee5774c4 make filter definition text field longer 2019-04-03 12:31:44 +00:00
zab2
b7d980df06 bump -3 for access filter 2019-04-02 17:39:32 +00:00
zab2
491cd0aa46 propagate from branch 'i2p.i2p.zab.2464' (head 47c50de0eaf4a41d0c0b2df3505ff3b885163791)
to branch 'i2p.i2p' (head a34db176d9f6313db1b8fd16926c8c2ca7e12e09)
2019-04-02 17:32:39 +00:00
zab2
e380b26798 Say that it's an absolute file 2019-04-02 16:51:26 +00:00
zab2
4790a14542 change UI to allow same filter definition to be used in multiple tunnels 2019-04-02 16:04:33 +00:00
zab2
194df9d88c link to format spec 2019-04-01 15:46:49 +00:00
zzz
567bccb51c Debian: Fixes for precise/trusty/jessie (ticket #2470) 2019-03-31 12:29:26 +00:00
zzz
0e8e3688f7 Data: Implement Destroyable for private keys (ticket #2462) 2019-03-31 12:23:19 +00:00
zzz
d3170de74a SAM prep for b33 2019-03-31 12:20:13 +00:00
zzz
908bf26151 javadoc fix 2019-03-31 12:18:44 +00:00
zab2
e55702b219 stop the filter in destroy method 2019-03-30 15:08:28 +00:00
zab2
c0c95827ef add logic to start and stop filter timers 2019-03-29 16:27:10 +00:00
zab2
fc9ad32878 Make the config format consistent (threshold rule [target]) 2019-03-29 15:36:03 +00:00
zzz
7d40dfe1e5 CLI tweak 2019-03-29 12:55:17 +00:00
zab2
2304e9b558 prettier html 2019-03-29 12:54:44 +00:00
zzz
944fe4794e Crypto: new SigContext (WIP) (proposal #148) 2019-03-29 12:54:12 +00:00
zzz
7501e3feea javadoc fix 2019-03-29 12:51:19 +00:00
zzz
eb0920e2c7 NetDB: Persistence for blinding cache 2019-03-29 12:50:41 +00:00
zab2
956a714d6e package.html 2019-03-29 12:44:44 +00:00
zab2
3f990b0bc8 html in javadoc 2019-03-29 12:42:45 +00:00
zab2
3dbe8f2003 document format 2019-03-28 19:47:08 +00:00
zab2
d90fc421fd javadoc 2019-03-28 18:57:42 +00:00
zab2
85db853d74 use curly braces around one-line for and while loops 2019-03-28 17:25:12 +00:00
zab2
440d5571fa Clear all state if the tunnel is closed 2019-03-28 17:22:08 +00:00
zab2
910a0d859d fix b32 parsing 2019-03-28 17:10:07 +00:00
zab2
c5f9aea557 do not use equalsIgnoreCase 2019-03-28 16:59:56 +00:00
zab2
84ea533b11 use DataHelper.split instead of String.split 2019-03-28 16:58:34 +00:00
zab2
fd2819c754 Use Hash objects instead of Strings representing b32s 2019-03-28 16:44:55 +00:00
zab2
fd6cb07e5d use SecureFileOutputStream 2019-03-28 16:25:36 +00:00
zab2
6d2270a1ed Cancel timers if tunnel is stopped 2019-03-28 15:32:49 +00:00
zab2
94bde1d821 Exception to be thrown in case of invalid filter definition 2019-03-28 14:46:19 +00:00
zzz
ba801be24f Debconf translation update from
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925515
2019-03-28 13:49:21 +00:00
zab2
e919271247 revert accidental commit 2019-03-28 13:37:51 +00:00
zab2
d2bdbcd27d correct io pattern 2019-03-28 13:31:39 +00:00
zab2
97eb5a56ab add the UI bits of the access rules 2019-03-28 02:04:21 +00:00
zab2
473ced4d4a disable splitting by tabs for now 2019-03-27 15:19:45 +00:00
zab2
c7771095d3 hook up loading of filter definitions for server tunnels 2019-03-27 15:04:04 +00:00
zzz
ea127d3fd4 NetDB: Fix b33 lookup looping after failure 2019-03-27 13:58:56 +00:00
zab2
b35762b4bb factory to rule them all 2019-03-27 13:24:55 +00:00
zab2
3f6fc7c0fb wip on parser of filter definitions 2019-03-27 13:05:31 +00:00
zzz
82eea0a8f9 NetDB: Cache blinding data for lookups and decryption (proposal #123) 2019-03-27 12:51:10 +00:00
zab2
670016e79c wip on parser of filter definitions 2019-03-27 12:45:26 +00:00
zzz
14492d7269 log fix 2019-03-27 12:38:40 +00:00
zzz
de9d968b76 DatabaseEntry: Change from volatile to synched 2019-03-27 12:32:23 +00:00
zzz
7bb7677604 SelfSignedGenerator: improve previous fix 2019-03-27 12:26:05 +00:00
zab2
841b16ef72 Access list may not exist 2019-03-27 11:39:17 +00:00
zab2
0d0dd1e241 hook up periodic events to ST2 2019-03-27 11:16:50 +00:00
zab2
62f7b2cece Skeleton architecture of access filter 2019-03-27 10:06:49 +00:00
zab2
a5e568ffa1 Hooks into streaming for filtering of incoming connections 2019-03-26 15:34:15 +00:00
zzz
64039ee3c2 button style 2019-03-23 17:43:57 +00:00
zzz
ce043943d9 SusiDNS: Add import feature (ticket #2447)
Box overlap issue remains todo, see ticket #2419
2019-03-23 16:42:37 +00:00
zzz
fea5bd4ada SelfSignedGenerator:
- Fix generation with Ed25519ph keys (ticket #2465)
- Increase serial number from 63 to 71 bits
2019-03-23 14:26:29 +00:00
zzz
00d4525325 Data: Initial work on b32 format for blinded leasesets (proposal 149, WIP) 2019-03-23 13:39:47 +00:00
zzz
f17776ec54 i2ptunnel: Escape {} in URLs (ticket #2130) 2019-03-22 15:41:16 +00:00
zzz
05845481d1 Debian files for 0.9.39 2019-03-22 15:28:48 +00:00
zzz
bb5a89219a 0.9.39 2019-03-21 12:11:48 +00:00
zzz
c3ebc00a86 bump for review 2019-03-17 15:56:49 +00:00
zzz
a57c277af0 Pull translations 2019-03-17 15:51:16 +00:00
zzz
2b00bfa58b Fix Debian builds with Jetty 9.4.15 (ticket #2457) 2019-03-16 16:54:36 +00:00
zzz
8962ea058f Doc updates, BuildTime update 2019-03-15 11:34:41 +00:00
zzz
7511de68a4 Router: Remove unused test support for AES disabled 2019-03-14 15:19:23 +00:00
zzz
0b5a36d5eb GeoIP update 2019-03-11 2019-03-14 13:23:15 +00:00
zzz
1f861c14a9 javadoc fix 2019-03-13 11:23:37 +00:00
zzz
d7d1dcb539 Crypto: Ed25519 check for S < L as in RFC 8032 2019-03-12 12:55:58 +00:00
zzz
91c59dfb6b Crypto: Fix Ed25519ph conversion 2019-03-12 12:37:28 +00:00
slumlord
9d17066175 Update hyperlinks for forum to point to i2pforum.i2p 2019-03-12 06:22:49 +00:00
zab2
7db602d959 Make I2pTunnel wait for router to reach RUNNING state (ticket #2377) 2019-03-11 20:00:04 +00:00
zzz
7e6fd01eef New home page icons from Sadie
Source: https://github.com/feathericons/feather#license Feather is licensed under the MIT License.
License: https://raw.githubusercontent.com/feathericons/feather/master/LICENSE
All icons converted from SVG to PNG, brightness adjusted, colourized with #848484 and resized to 32x32
modifications:
group_gear - feather icon code layered with message - square. Message- square icon resized. 
plugin_link - feather icon coffee layered with square. Coffee icon cropped to leave" prongs" 
plugin. - feather icon coffee layered with plus square. Coffee icon cropped to create "prongs"
i2psnark - feather icon underline - layer added, "U" rotated , line cut and copied over, them cut out to create "magnet.
2019-03-11 15:56:25 +00:00
zzz
365f5a8c7b UPnP redundant casts 2019-03-10 12:58:23 +00:00
zzz
30dbe24777 LS2: Allow UTF-8 for blinding secret 2019-03-10 12:11:13 +00:00
meeh
e36a3b318a Mac OSX Launcher:
* Fixed startup option so the launcher can start at OSX login/bootup.
* Added I2P Browser to the list of "firefox" browsers to detect.
* Changed hardcoded path lookup to native "registry" lookup for firefox application.
* Made the advanced preferences table editable by the user.
* Cleanup of old and/or unused code.
* Bugfixes.
2019-03-10 11:16:56 +00:00
zzz
5d389c8855 I2CP: Add support for blinding secret 2019-03-09 16:40:15 +00:00
zzz
d6a53cc3a6 Data: Consolidate offline key check
i2ptunnel: Prevent registration auth if key offline
2019-03-09 11:47:03 +00:00
zzz
409207e02d more selectors 2019-03-07 15:01:10 +00:00
zzz
95366c06ce NetDB: Minor performance improvement in selectors
log tweaks
2019-03-07 14:46:20 +00:00
zzz
5b1b4acd2c NetDB: Fix flood version check, add version check for RedDSA 2019-03-06 15:28:47 +00:00
zzz
10bae6a07b Data: Update Encrypted LS2 blinding and encryption to match current proposal 123
Hide b32 in console for encrypted LS2
2019-03-05 15:43:23 +00:00
zzz
bfafdd34be NetDB: Fix tunnel selection for verify of encrypted ls2 store
Fix NPE handling lookup of encrypted ls2
2019-03-04 19:04:42 +00:00
zzz
0b2896516e Console: Fix NPEs displaying encrypted LS2 2019-03-04 18:37:01 +00:00
zzz
268a3ee5f5 NetDB: Fix finding tunnels to publish encrypted LS2
log tweaks
2019-03-04 17:38:26 +00:00
zzz
ad1600eb51 log tweaks 2019-03-04 17:37:29 +00:00
zzz
f1ed870a4a Data: Fix NPE in debug logging 2019-03-04 17:17:44 +00:00
zzz
5d3b7c1c53 NetDB: Call fail callback when lookup is negative cached (thx zab) 2019-03-04 17:07:45 +00:00
zzz
cd97718682 I2CP, NetDB: More encrypted LS2 fixes (WIP)
Marked encrypted LS hash as local
Fix isCurrent() on encrypted LS
Fix unpublish of encrypted LS
2019-03-04 17:06:01 +00:00
zzz
54d9a29855 I2CP, NetDB, Console: Encrypted LS2 handling fixes (WIP)
log tweaks
2019-03-02 21:52:12 +00:00
zzz
7cbb43ab75 I2CP: Encrypted LS2 handling fixes, log tweaks (WIP)
Add number of privkeys field to CreateLeaseSet2 message
Check all privkeys, not just the first, on router side
2019-03-02 19:53:16 +00:00
zab2
335736b2b7 Fix log strings 2019-03-02 18:13:55 +00:00
zzz
f0b9986e67 Enc LS2 debug logging changes 2019-03-02 16:00:56 +00:00
zzz
82d187438f Streaming: Fix sending messages with expired times (ticket #2451) 2019-03-01 18:00:54 +00:00
zzz
d1617dd0b6 Console: Fix router logs not shown if first msg is a dup 2019-02-28 16:55:16 +00:00
zzz
21c7a341fb Console: Change fallback client names to use b32
instead of truncated b64. Anchors remain b64.
2019-02-28 16:07:58 +00:00
zzz
302adc2d16 Console: Drop icons for deleted /home items 2019-02-27 15:15:55 +00:00
zzz
c8b7e829db Console: Handle zero SSU RTT on /peers (ticket #2443)
PeerState minor cleanups
2019-02-26 17:38:34 +00:00
zzz
cf1c0cb3ed SSU: Fix RTT/RTO calculations (ticket #2443) 2019-02-26 17:17:00 +00:00
zzz
566df1c275 SSU: Fix scheduling of peer test at startup (ticket #2441) 2019-02-26 16:19:36 +00:00
zzz
16421fa0b6 NTCP: Fix number of SendFinisher threads (ticket #2438) 2019-02-25 15:58:29 +00:00
zzz
3c911ee298 I2CP: Strip i2p.reseedURL from session options take 2 2019-02-25 15:10:34 +00:00
zzz
a12058db3a I2CP: Strip i2p.reseedURL from session options 2019-02-25 15:05:14 +00:00
zzz
7ce539a815 NetDB: Fix dup publish of RI at startup
Improve locking for checking address change
Publish RI after netdb is ready
log tweaks
2019-02-25 14:40:59 +00:00
zzz
b76b2ef206 Console: Flip order of router logs 2019-02-23 18:02:00 +00:00
zzz
32797dd415 NTCP: Loop in pumper if more to write (ticket #2440) 2019-02-23 17:06:01 +00:00
zzz
e1385a71e2 minor speedup 2019-02-23 17:03:52 +00:00
zzz
9cd90b0530 NetDB: Use published date, not earliest lease expiration, for LS2 comparisons
Fix earliest LS expiration adjustment when publishing for LS2,
so .38 routers won't reject as not newer
Don't start new store after verify fail if we've already done so
Increase flood candidates for LS2
Version checks for encrypted LS2
FVSJ cleanups
log tweaks, javadocs
2019-02-23 17:03:04 +00:00
zzz
5440a3402f I2CP: Force i2cp.leaseSetType option for offline keys 2019-02-21 16:16:27 +00:00
zzz
9fafc253b7 Data: Always set unpublished flag for inner LS (Enc LS2)
Fix setDestination()
2019-02-21 14:58:58 +00:00
zzz
b37160fa8d Crypto: Keygen for RedDSA, allow RedDSA for unblinded keys (Enc LS2) 2019-02-21 14:19:38 +00:00
zzz
7fbe1ced5a Crypto: Sign/verify/encrypt/decrypt for Encrypted LS2
generateAlpha() method for arbitrary date
2019-02-20 22:49:14 +00:00
zzz
17270b1502 Crypto: RedDSAEngine and generateAlpha() for Encrypted LS2 2019-02-20 15:00:54 +00:00
zzz
e34b646231 Crypto: New ChaCha20 wrapper around ChaChaCore, for use with Encrypted LS2 2019-02-19 19:11:34 +00:00
zzz
14ac8fe545 Crypto: Move ChaChaCore from router to core, in prep for use with Encrypted LS2 2019-02-19 16:00:47 +00:00
zzz
b3c5974693 Crypto: Implement blinding (proposal 123)
Add sig type 11 for blinded keys
2019-02-19 13:12:26 +00:00
slumlord
af46e48563 Fix i2psnark-standalone.zip build which broke after themes were removed 2019-02-19 06:33:16 +00:00
zzz
2aa093754d Tomcat 8.5.38 2019-02-18 18:44:37 +00:00
zzz
ab7f61d220 Console: Drop midnight and classic themes (ticket #2272) 2019-02-18 18:14:28 +00:00
zzz
2d67d11537 Transport: Fixes for NTCP when SSU disabled (ticket #1417)
Delay port forwarding until after UPnP rescan complete
WIP
2019-02-18 17:55:17 +00:00
str4d
d244d17363 Gradle: Optionally include jbigi at runtime for core
This enables running the benchmarks with jbigi present:

./gradlew -Pwith.jbigi jmh --no-daemon
2019-02-17 15:42:15 +00:00
str4d
e662f09838 Gradle: Create jbigi configuration 2019-02-17 15:41:17 +00:00
str4d
ad5301ae10 Gradle: Integrate JMH benchmarks
Run with ./gradlew jmh --no-daemon
2019-02-17 09:49:03 +00:00
str4d
def939284c Gradle: Disable ScalaTests when TARGET_JAVA_HOME is set
Previously, ScalaTests were only disabled when running Gradle with JDK 7.
Gradle 5+ only runs on JDK 8+, so when cross-compiling and testing JDK 7
we need to check for this state and disable ScalaTests.
2019-02-17 09:30:53 +00:00
str4d
f9c13968a8 Travis CI: Test against JDK 9+ 2019-02-17 09:23:12 +00:00
str4d
4f6b58e5af Gradle: Configure --release compiler flag after project evaluation 2019-02-17 02:35:26 +00:00
str4d
2556c7755b Travis CI: Update config to handle cross-compilation 2019-02-17 02:33:19 +00:00
str4d
9731c203bd Gradle: Improve cross-compilation support
JDK 9+ have a --release flag that correctly configures the bootClasspath.
For JDK 8 we now enforce manual configuration.
2019-02-17 02:13:32 +00:00
str4d
a1b67e3720 Gradle: Parse router version from Java source 2019-02-17 01:56:24 +00:00
str4d
56c1739d54 Gradle: Use plugins DSL where possible 2019-02-17 01:27:05 +00:00
str4d
1ae987927b Upgrade Gradle wrapper to 5.2.1 2019-02-17 01:16:20 +00:00
zzz
51b27bbf0c Console: Hide disabled transports on /peers 2019-02-08 13:58:38 +00:00
zzz
5b78b53fe8 SSU: EstablishmentManager fixes (ticket #2397) 2019-02-08 13:24:42 +00:00
zzz
3ba0fcf6da SAM: Support offline keys 2019-02-07 20:27:42 +00:00
zzz
7544d0a590 Streaming: Fix exception after sig verify fail
log tweaks
2019-02-07 18:14:18 +00:00
zzz
636016d107 NTCP: Add option to disable NTCP1 (ticket #2328)
Don't bid for outbound-only NTCP2 addresses
Fix NTCP2 cost when transitioning to inbound
2019-02-07 14:54:56 +00:00
zzz
b310c60188 Javadoc fixes 2019-02-06 12:48:33 +00:00
zzz
19cb85a74d i2pcontrol: Javadoc fixes 2019-02-06 12:45:21 +00:00
zzz
490b81c1a1 Crypto: Shortcut GroupElement representation conversion 2019-02-06 12:35:27 +00:00
zzz
3a30f07483 I2CP: Prevent use of repliable datagrams with offline keys 2019-02-06 11:54:29 +00:00
zzz
61c62424c2 Build: Add targets for alternate debian distros (ticket #2410) 2019-02-06 11:48:48 +00:00
zzz
16ccc1bea5 remove exchanged.i2p 2019-02-06 11:46:23 +00:00
zzz
b82702393f NTCP: Speed up allowConnection() (ticket #2381) 2019-02-05 16:44:09 +00:00
zzz
8a77db15d5 Transport: Clean up unreachable() methods (ticket #2382) 2019-02-05 15:39:00 +00:00
zzz
beb0879f24 Router: OutNetMessage cleanup (ticket #2386) 2019-02-05 15:19:29 +00:00
zzz
6f75680a7e SSU: PacketHandler cleanup (ticket #2383) 2019-02-05 14:57:10 +00:00
zzz
a756c12432 I2CP: Change format and message type of CreateLeaseSet2 message
to match spec changes
2019-02-04 21:58:27 +00:00
zzz
ead49256c7 Data: Represent blinding secret as a SigningPrivateKey 2019-02-04 16:58:41 +00:00
zzz
0e029f84b0 I2CP: Fix LS2 NPE 2019-02-03 19:03:28 +00:00
zzz
bd6cf53d53 i2ptunnel: Fix HTTP websockets by passing through
Connection headers containing "upgrade" (ticket #2422)
Server-side change only. Client-side in previous commit.
2019-02-03 17:29:16 +00:00
zzz
e20a6a9685 i2ptunnel: Fix HTTP websockets by passing through
Connection headers containing "upgrade" (ticket #2422)
Client-side change only. Server-side todo.
2019-02-03 16:31:26 +00:00
zzz
0e710f8785 Streaming: Support offline signatures (proposal 123)
Don't send FROM in RESET, not required since 0.9.20
Send RESET when SYN signature verification fails
Use cached buffers for signature verification
Move setOptionalFrom() from Packet to PacketLocal
Always verify packets with signatures, even if not required
AIOOBE checks
cleanups, log tweaks
2019-02-03 13:41:42 +00:00
zzz
7d11fb269e I2CP: Remove revocation private key from CreateLeaseset2 message
Use correct key to sign SessionConfig with offline keys
LeaseSetKeys cleanups
2019-02-03 12:59:53 +00:00
zzz
d7808cd16d Data: Fix length for offline sig verification 2019-02-03 12:49:56 +00:00
zzz
f288682436 Test: Disable NTP in LocalClientManager 2019-02-03 12:47:33 +00:00
zzz
19defbe05d Debian: Fix build of i2pcontrol 2019-02-02 13:28:59 +00:00
zzz
175ea0f0c2 i2ptunnel: Update clearnet UA to match current TBB 2019-02-01 19:07:22 +00:00
zzz
30015c1933 i2ptunnel: Handle PUT like POST 2019-02-01 13:49:13 +00:00
zzz
4f8455040e i2ptunnel: Caching of outproxy selection, avoid last-failed outproxy 2019-02-01 13:39:57 +00:00
zzz
428fb269f0 Debian: AppArmor fix for Oracle JVM (ticket #2319)
Allow any JRE or JDK to work
2019-02-01 13:11:12 +00:00
zzz
ec5e2dba94 i2ptunnel: More localhost checks 2019-02-01 13:03:40 +00:00
zzz
316011e047 Debian: Fix version detection of Tomcat 9 required for reproducible builds 2019-01-31 11:55:43 +00:00
zzz
68567cb531 Build: Fix javac.classpath in junit.compileTest targets (ticket #2333) 2019-01-30 20:51:17 +00:00
zzz
4eb9368830 I2CP: Fixes for CreateLeaseset2 message with multiple keys 2019-01-30 20:23:09 +00:00
zzz
c555bb6c93 i2cp.leaseSetEncType param:
Support comma-separated values,
check param in session config,
support stored EncTypes in private keys.
Show types and multiple keys on LS debug page
2019-01-30 19:33:15 +00:00
zzz
1bb57c4103 EdDSA minor cleanup 2019-01-29 13:51:42 +00:00
zzz
a51a6d57f9 rename class 2019-01-29 13:28:11 +00:00
zzz
8465fe7717 fix build warnings 2019-01-28 15:22:17 +00:00
zzz
0801d20fd1 EdDSA: Make more classes serializable (Github PR #68) 2019-01-28 15:21:15 +00:00
zzz
9055982cf0 bump after prop 2019-01-28 15:17:51 +00:00
zzz
8c9ce56837 propagate from branch 'i2p.i2p.zzz.i2pcontrol' (head 1334d424003d201aa352cf57a6ba2f61241ef363)
to branch 'i2p.i2p' (head fe8a90fdbdd491e16040e3ed91a35faa72fd78f2)
2019-01-28 15:10:30 +00:00
zzz
0a8ab44139 I2PControl: Add manifest for jar build
Stub out socketJar build
2019-01-28 14:14:29 +00:00
zzz
24fd48815a I2PControl:
Disable webapp by default
Add link in Services section of sidebar
Add definition in PortMapper
Add stub controller for socket implementation, WIP
Javadocs
2019-01-28 13:31:54 +00:00
zzz
3fca0f6f99 LS2: Honor unpublished flag 2019-01-27 16:13:05 +00:00
zzz
3cd12ecefc LS2: Select first supported encryption key from leaseset
OCMOSJ: Fail if unsupported crypto or bad ls type
2019-01-27 15:59:34 +00:00
zzz
0889a751db NDT:
Catch exception on DNS lookup failure (ticket #2399)
Add support for specifying server in CLI (ticket #2413)
Finals and javadocs
2019-01-27 14:25:48 +00:00
zzz
efb1b7c24a Debian: Fix PPA builds for precise and trusty (ticket #2408)
Reverts fix for #2329 for these distros
2019-01-26 18:34:10 +00:00
zzz
3527f251c8 Debian: Add build option for libtomcat9 (ticket #2364) 2019-01-24 14:15:04 +00:00
zzz
6cdc515cfd Fix Debian control files (ticket #2401) 2019-01-24 12:43:02 +00:00
zzz
57de4b1805 Debian files for 0.9.38 2019-01-24 12:29:22 +00:00
meeh
609d5944bb Mac OSX Launcher: 0.1.3 Release commit. 2019-01-22 19:25:33 +00:00
zzz
88d9f1d509 0.9.38 2019-01-22 11:54:19 +00:00
zzz
5c0aab4190 Minor fixes after review 2019-01-21 21:57:14 +00:00
zzz
33e96d7841 Reseed: Update SSL cert 2019-01-21 21:56:34 +00:00
zzz
d00e3c77ab Debian: Add source param to javadoc target, fixes build on sid 2019-01-20 13:28:22 +00:00
zzz
318ebb3fc5 Debian: Replace ttf-dejavu with fonts-dejavu (ticket #2395) 2019-01-20 13:24:01 +00:00
zzz
f224a770f0 bump for review 2019-01-18 20:47:08 +00:00
zzz
ebcf187df6 Pull translations 2019-01-18 20:41:44 +00:00
zzz
b3cfc89fa2 remove old file from test script 2019-01-18 20:34:09 +00:00
meeh
e57606a9f6 Mac OSX Launcher: Added Carthage file + shell script bumpInfoPlist.sh 2019-01-18 16:30:46 +00:00
meeh
a36777882e Mac OSX Launcher: Misc changes + xcode project file update 2019-01-18 16:30:03 +00:00
meeh
605f9872cd Mac OSX Launcher: UI code updates, integration of firefox manager. 2019-01-18 16:29:12 +00:00
meeh
52125917b4 Mac OSX Launcher: Storyboard updates, added firefox button, preferences changes etc. 2019-01-18 16:28:17 +00:00
meeh
ba853a8c97 Mac OSX Launcher: The firefox manager code 2019-01-18 16:26:08 +00:00
meeh
6ad64d5b44 Mac OSX Launcher: Adding the "launcher launcher" for startup functionality. 2019-01-18 16:25:01 +00:00
zzz
272588d820 Debian: Add Disco files, refresh patch for Jetty 9.4 2019-01-18 14:32:28 +00:00
zzz
344c812666 NTCP: Stop X25519KeyFactory on shutdown (ticket #2388) 2019-01-18 12:15:43 +00:00
zzz
b4e2619c3b Plugins: Fix loading of webapp configuration classes
on Jetty 9.4 by whitelisting them as allowed server classes
(ticket #2385)
2019-01-18 11:35:36 +00:00
zzz
6ca383071b Debian: AppArmor updates (ticket #2319) 2019-01-16 20:10:36 +00:00
zzz
d851631494 SusiMail: Fix sending mail with attachments (ticket #2373)
Fix deleting attachments from drafts
Fix dup attachments after clicking add attachment without browsing first
Fix update of draft folder after saving as draft
Change text of add attachment button for clarity
Debug logging
2019-01-15 17:18:59 +00:00
zzz
16f4f04092 change firefox profile installer link 2019-01-15 16:05:40 +00:00
zzz
ca86bbe4f7 EncType javadoc update 2019-01-14 15:58:40 +00:00
zab2
cf27938983 fix compilation with Gradle to account for GeoIP2 and systray changes 2019-01-13 14:04:03 +00:00
zzz
4283d71b92 I2CP: Set LS2 unpublished bit, show in debug output 2019-01-13 13:14:58 +00:00
zzz
10f2d838c9 SSU: More consolidation of clock().now() calls 2019-01-12 13:45:38 +00:00
zzz
f5ca17c844 NetDB: Use isSlow() in floodfill criteria 2019-01-12 13:43:09 +00:00
zzz
b62732b5b3 Console: More LS2 debug output
I2CP: Bump min LS2 router version for release
2019-01-11 14:44:33 +00:00
zzz
47beb8250e propagate from branch 'i2p.i2p' (head ff155397f79c33f8f6767c2c120e57cb7dd30d88)
to branch 'i2p.i2p.zzz.i2pcontrol' (head 9e68613e29f1a3bd5a4e2b3d8c5637b48f499e5e)
2019-01-11 13:51:41 +00:00
zzz
17228def91 I2CP: Remove client-side-only options from those sent to router 2019-01-10 17:08:35 +00:00
zzz
5ca98022ab I2CP: Router-side stub for enc. ls2; throw for now 2019-01-10 16:21:48 +00:00
zzz
0c15936b5d I2CP: Router-side fix for meta LS2 2019-01-10 15:37:11 +00:00
zzz
e02a0dfc5b NTCP: Avoid Java 8/9 bootclasspath issue 2019-01-10 14:17:18 +00:00
zzz
0d330caf9a I2CP: Basic router-side handling of meta LS2
Improve error handling of LS2 params client-side
Methods to remember blinded key in LS2
2019-01-10 13:39:18 +00:00
zzz
8cd7e7de65 poupdate-source for 0.9.38
Fix poupdate script to not pick up tags in 3rd party libs
2019-01-09 19:03:41 +00:00
zzz
671e9dd711 I2CP: Stub out client-side creation of meta and enc. LS2 2019-01-09 18:41:36 +00:00
zzz
4ff9092bd9 Wrapper: Increase default heap to 256 MB 2019-01-09 13:29:36 +00:00
zzz
fb8665b9bd Console: Fix broken image link on /configui 2019-01-09 13:09:49 +00:00
zzz
2c7033001e Console: Remove firefox anchor in link 2019-01-09 13:08:45 +00:00
zzz
30ea6f3ffa Console: Remove test code that forces wizard run on dev builds 2019-01-09 13:07:59 +00:00
zzz
5634055d4b Crypto: Stub out EdDSA blinding (proposal 123) 2019-01-05 14:22:46 +00:00
zzz
3b7284c9cd I2CP: Add support for multiple private keys in CreateLS2Message 2019-01-04 14:30:38 +00:00
zzz
74ed974145 NetDb: Prevent ISJ deadlock (ticket #2366) 2019-01-04 13:48:38 +00:00
zzz
4786081026 Build: Check cert validity
Reseed updates
2019-01-04 12:15:58 +00:00
zzz
150cee9a08 Data: Add type byte to MetaLease,
add EmptyProperties to reduce object churn,
undeprecate getSigningKey(),
reduce loadProps() buffer size
2019-01-02 14:29:10 +00:00
zzz
941a994482 remove temp wizard text 2019-01-02 13:23:30 +00:00
zzz
d10d722763 Wizard: Styling, fix links, change button icons
back.png: Arrow flipped from go.png in Gimp, same license
2019-01-02 13:19:12 +00:00
zzz
9951e3467e Data: More work on Encrypted LS2 (proposal 123) 2019-01-02 11:50:05 +00:00
zzz
62fd0497f8 Debian: Split up conffiles into subpackages 2019-01-01 21:01:40 +00:00
zzz
a0d2288ded Debian: Remove obsolete systray.config 2019-01-01 20:20:35 +00:00
zzz
149359fdc3 Data: Fix LS2 size(), fix Meta LS2, fix date rouding 2019-01-01 20:17:56 +00:00
zzz
4ae57f4f01 Data: Fix LS2 support for unknown enc. types (proposal 123) 2019-01-01 17:48:31 +00:00
zzz
d95d81aea7 Data: Add support for LS2 multiple encryption keys (proposal 123) 2019-01-01 17:14:37 +00:00
zzz
92ad4d1ce3 NBI: Add lookup tables for ARMv8 2019-01-01 15:41:11 +00:00
zzz
3c0ba5ce9c Console: Add warning for OpenJDK Zero VM 2019-01-01 15:01:22 +00:00
zzz
f221e724b9 Console: New light background (ticket #738) thx Alex 2019-01-01 14:43:19 +00:00
slumlord
0fdede8657 Fix _isArm 2018-12-30 13:17:19 +00:00
zzz
47629bf2cf Console: Update ARM warning (ticket #2368), remove Java 11 warning 2018-12-24 13:24:58 +00:00
zzz
0474876b58 NDT: Fix deprecation 2018-12-24 13:21:05 +00:00
zzz
edae8e3e0b Sybil: Translate strings that we already have tagged elsewhere 2018-12-23 15:02:45 +00:00
zzz
1411d0cff3 Sybil: Change persistence format to prevent errors in some locales 2018-12-23 14:40:13 +00:00
zzz
aad80eb2a3 Console: _action cannot be null in processForm()
GraphHelper minor cleanup
2018-12-23 13:38:54 +00:00
zzz
af49a90303 Sybil: Add background run form 2018-12-23 13:21:27 +00:00
zzz
fa6a4ca1d1 Console: Convert NetDbHelper to a FormHandler,
change SybilRenderer forms to POST,
only collect RIs on required Sybil tabs
2018-12-23 12:19:32 +00:00
zzz
e122393914 FormHandler: move things around 2018-12-23 11:08:50 +00:00
zzz
2d026d5ae7 Console: isAdvanced() cleanup 2018-12-23 10:17:46 +00:00
zzz
367e5ac679 javadoc fix 2018-12-21 12:15:07 +00:00
zzz
f3a4b115f3 Console: More links on sybil page 2018-12-21 11:37:09 +00:00
zzz
9f64cc7c60 TLSv1.3 notes 2018-12-21 11:35:15 +00:00
zzz
03651292fb thread name change 2018-12-21 11:33:55 +00:00
zzz
94fd60db10 Transports: Improve banning of routers from wrong network 2018-12-21 11:32:17 +00:00
zzz
18b7d97584 new reseed 2018-12-20 11:02:20 +00:00
zzz
021375b5d5 NTCP: More now() calls out of loops 2018-12-20 10:58:30 +00:00
zab2
8a0602732d Get call to system timer out of tight loop when counting connections 2018-12-19 10:51:53 +00:00
zzz
20876ff307 Sybil page date formatting 2018-12-17 14:43:02 +00:00
zzz
bf3a7d6ef7 Data: More work on Encrypted LS2 (proposal 123) 2018-12-17 13:59:49 +00:00
zzz
35a771c764 NTCP2: Use new HKDF class 2018-12-17 13:16:54 +00:00
zzz
eb8178ea3b Sybil: Linkify IP reasons
Adjust IP points
2018-12-17 11:46:14 +00:00
zzz
3867beb198 GeoIP: Fix NPE (thx parg) 2018-12-17 11:24:27 +00:00
zzz
cae5dcd69c Sybil: Refactoring part 6
Make Analysis class a JobImpl, run on configured frequency
Bug fixes and cleanups
2018-12-17 11:23:08 +00:00
zzz
2a805dddf5 Sybil: Refactoring part 5
Make Analysis class singleton, hang off ClientAppManager
prep for offline scheduling
2018-12-16 14:44:37 +00:00
zzz
fa0d63f40f Sybil: Refactoring to separate analysis and display, part 4
Load/store offline analysis
Split up sections into separate tabs
2018-12-16 13:20:59 +00:00
zzz
9437e2cb79 Sybil: Refactoring to separate analysis and display, part 3 2018-12-15 17:49:52 +00:00
zzz
3054a240bb Sybil: More refactoring to separate analysis and display 2018-12-15 16:54:01 +00:00
zzz
5d06de8608 Sybil: Class for persisting results, related refactoring 2018-12-14 16:54:10 +00:00
zzz
468871f21e Crypto: Add HKDF class for LS2 and NTCP2 (proposal 123)
Minor speedup in HMAC256
2018-12-13 14:39:08 +00:00
zzz
6c3c227c1b Debian: Add alt files for sid (ticket #2098)
Fixes compatibility with Jetty 9.4
Patch from Emmanuel Bourg, see
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916177
Briefly tested by mhatta
2018-12-13 14:30:22 +00:00
zzz
9738db7254 UrlLauncher:
- Use arrays for exec
- Randomize temp file name
- Require quotes around args containing spaces in routerconsole.browser property
- Add debug logging
- Add chromium-browser to the default list
- Parse and use full command line from Windows registry
- Replace %1 with url in registry line and routerconsole.browser property
ShellCommand:
- Switch to i2p logging
2018-12-12 20:12:07 +00:00
zzz
51bf23a34c DTG: Use UrlLauncher to launch browser 2018-12-12 15:17:51 +00:00
zzz
5eda30644f Util: Add another ShellCommand String[] method
to be used by UrlLauncher
2018-12-12 13:59:27 +00:00
zzz
2746ed5ce2 Installer: Drop unused systray.config 2018-12-12 13:56:47 +00:00
zzz
fd23b23e56 Crypto: HMAC-SHA256 cleanup
Add byte[] key method to reduce object churn in NTCP2
Un-deprecate in context
2018-12-11 12:19:46 +00:00
zzz
a63d2dccb2 Transports: Log tweaks 2018-12-11 11:35:45 +00:00
zzz
0f6f8f90c9 Utils: Code to simulate IPv6-only 2018-12-11 11:32:52 +00:00
zzz
87c97b2a0a Debian: Add conffiles list
Users shouldn't be editing these, they are the site templates
that are copied to the config dir on first run, but if they are changed,
the user will have the chance to save the changes on upgrade.
2018-12-11 11:28:00 +00:00
zzz
6f4d76e871 editorconfig update 2018-12-11 11:22:43 +00:00
zzz
c1850cc4f3 Utils: Enable TLSv1.3 for SSL sockets
(available in Java 11)
2018-12-11 11:19:36 +00:00
zzz
399899e7e7 NetDb: Allow longer expiration for Meta LS2 2018-12-08 18:24:14 +00:00
zzz
bdc4d82eb2 Transport: Don't set status to disconnected if IPv6-only but not configured IPv6-only 2018-12-08 17:35:29 +00:00
zzz
2200cf6627 Transport: Don't repeatedly publish RI if IPv6-only but not configured IPv6-only 2018-12-08 17:28:54 +00:00
meeh
d382f1214e merge of 'a2e8a7d9b157e9a7d5ab0e4356b7b046715a4243'
and 'c3ae5fc1d281c2f9c6357dd72bfc2147bae71877'
2018-12-08 14:38:18 +00:00
meeh
36a5790b87 Mac OS X Launcher: Misc minor updates to Preferences 2018-12-08 14:37:59 +00:00
zzz
5d100417c4 Console: Hide I2CP config if disabled 2018-12-08 14:30:04 +00:00
meeh
b946bb0679 Mac OS X Launcher: Webkit header + I2P version inside Info.plist 2018-12-08 09:17:09 +00:00
meeh
c3b8317edb Mac OS X Launcher: Adding optional Dock Icon functionality 2018-12-08 09:16:28 +00:00
meeh
f90e2ee659 Mac OS X Launcher: Xcode metadata project file update 2018-12-08 09:15:33 +00:00
meeh
3bad8f33c4 Mac OS X Launcher: Remove unneeded entitlement 2018-12-08 09:15:04 +00:00
meeh
dfcc616cb3 Mac OS X Launcher: Misc changes in ObjC, forwarding sendUserNotification to Swift. 2018-12-08 09:14:33 +00:00
meeh
a0d356bc56 Mac OS X Launcher: Changes in path lookups (many via Preferences), launchd template changes and java arguments for the router itself. 2018-12-08 09:12:24 +00:00
meeh
f4496a0c4c Mac OS X Launcher: Unfinished experimental code, adding so other people can compile the xcode project. 2018-12-08 09:10:43 +00:00
meeh
8841fed1f1 Mac OS X Launcher: Updated version.h template file to embedd i2p version as NSString in build time. 2018-12-08 09:09:37 +00:00
meeh
eca5805195 Mac OS X Launcher: Adding selectors for Preferences window launch, and for view of experimental console webview. 2018-12-08 09:08:22 +00:00
meeh
b8681ddf9d Mac OS X Launcher: Misc updates to the Launchd code, also moved it to a own directory for cleaner source view. 2018-12-08 09:07:03 +00:00
meeh
68ad4eec14 Mac OS X Launcher: Adding user interface classes for the different Preferences views so far. 2018-12-08 09:05:55 +00:00
meeh
a192679638 Mac OS X Launcher: Adding Preferences class which works as an interface towards apple's "defaults" preferences system 2018-12-08 09:04:54 +00:00
meeh
7058bd85fa Mac OS X Launcher: Adding Preferences button to existing storyboard view 2018-12-08 09:03:42 +00:00
meeh
92c42db787 Mac OS X Launcher: Adding Preference storyboard 2018-12-08 09:03:13 +00:00
zzz
926bce78a7 I2CP: Set and validate offline sig in SessionConfig 2018-12-05 15:27:36 +00:00
zzz
d054c6bc04 I2CP: Set offline keys in generated LS2
(router side to follow)
Propagate error from disconnect message to session listener
Refactor RLSMH options
2018-12-05 13:50:07 +00:00
zzz
2876da2565 I2CP, Data: Initial support for LS2 offline keys in I2PSession and PrivateKeyFile 2018-12-04 20:59:38 +00:00
zzz
177f595f33 Javadoc fixes
NDT log tweaks
2018-12-04 20:34:51 +00:00
zzz
7c5162e155 I2CP: Move the port 7654 definition 2018-12-03 16:17:30 +00:00
zzz
5e7a277e98 I2CP: Consolidate all the port 7654 definitions 2018-12-03 15:22:36 +00:00
zzz
af2eea5916 NetDb: Don't send our RI in response to DSM when shutting down
reverts change from 2015
2018-12-03 12:23:57 +00:00
zzz
633a75e286 Wizard: Update text 2018-12-03 12:03:27 +00:00
zzz
6e053689b9 Transport: Add methods to force-disconnect a peer 2018-12-02 19:14:36 +00:00
zzz
ee722b7688 Router: Allow LS2 DSM down a tunnel 2018-12-02 18:53:13 +00:00
zzz
e6912453e0 DataHelper: Minor efficiency improvements in Properties methods 2018-12-02 15:21:30 +00:00
zzz
7c928f99ea Router: Only flood LS2 to router that supports it
Use same version check in StoreJob for flooding
2018-12-01 18:31:58 +00:00
zzz
9efa0eaa40 Router: Only send/verify LS2 with router that supports it
Remove old commented-out code
2018-12-01 18:18:59 +00:00
zzz
700d4d3b48 Console: Don't output tunnel IDs for meta LS
Router: Don't try to send to a meta LS in OCMOSJ
2018-12-01 16:27:53 +00:00
zzz
026ddb3278 Router: Add preliminary support for more LS2 types (proposal 123)
I2CP: Don't require privkeys for meta in CLS2 message
2018-12-01 13:13:51 +00:00
zzz
79440f84eb I2CP: Add preliminary support for LS2 (proposal 123) 2018-12-01 11:40:10 +00:00
zzz
922515dfe4 Crypto: Add X25519 keygen support 2018-11-30 17:29:08 +00:00
zzz
f1689187a4 Data: Check data length in typed constructors
Check for type match in KeyPair
Mark placeholder EncTypes 1-3 as unavailable
2018-11-30 15:56:27 +00:00
zzz
2487bca47c Crypto: Change X25519 key classes from Java keys to I2P keys,
in prep for new crypto (Proposal 144)
Add EncType
Fix PrivateKey constructor w/ EncType
Add support to KeyGenerator
2018-11-30 15:15:31 +00:00
zzz
cc4da1b4da Crypto: Move Curve25519 from router to core,
in prep for new crypto
2018-11-30 13:51:50 +00:00
zzz
a8bacd8727 Data: Change LS2 sign/verify to match proposal changes 2018-11-27 12:34:41 +00:00
zzz
b93be8bb4a Crypto: Define ElG length constants 2018-11-25 15:23:17 +00:00
zzz
9badfd07bf Utils: Catch ProviderException in SelfSignedGenerator (ticket #2344) 2018-11-25 15:17:27 +00:00
zzz
dc8a822b0e GeoIP: Reduce object churn, add test to command line tools 2018-11-25 15:16:18 +00:00
zzz
43e0d4f910 Reseed: Drop manas.ca reseeds as requested 2018-11-25 15:13:12 +00:00
zzz
d4caafb592 Bundle I2PControl 0.12, as a console webapp
Includes mods to use org.json.simple package.
See licenses/LICENSE-Apache2.0.txt
Includes jBCrypt:
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
See licenses/LICENSE-jBCrypt.txt
Includes jsonrpc2 libs:
See licenses/LICENSE-Apache2.0.txt
http://software.dzhuvinov.com/json-rpc-2.0-server.html
Jars from maven central:
jsonrpc2-base-1.38.1-sources.jar  22-Oct-2017
jsonrpc2-server-1.11-sources.jar  16-Mar-2015
2018-11-25 13:26:43 +00:00
zzz
d6e350184c Test: Move ElGamalTest from core to router to follow tested class 2018-11-23 14:22:08 +00:00
zzz
535f2daab0 Router: Move ElGamalAESEngine from core to router
Client end-to-end crypto removed 13 years ago
Not used by any client, app, or plugin.
2018-11-23 13:04:28 +00:00
zzz
5c0c69c654 GeoIP: Add MaxMind GeoLite2-Country database 2018113, gzipped
Database and Contents Copyright (c) 2018 MaxMind, Inc.
This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
This database incorporates GeoNames [http://www.geonames.org] geographical data,
which is made available under the Creative Commons Attribution 3.0 License.
To view a copy of this license, visit http://www.creativecommons.org/licenses/by/3.0/us/.
- Drop old ipv4 and ipv6 data files and build scripts
- Build changes for new file
2018-11-20 14:25:49 +00:00
zzz
ef44c36f0c GeoIP: Hook maxmind geoip2 code into transport lookup. 2018-11-20 14:14:34 +00:00
zzz
f1297e7c62 GeoIP2: License and javadocs 2018-11-20 11:07:33 +00:00
zzz
21ca75da14 Modify GeoIP2-java
to remove the dependency on the large com.fasterxml.jackson.databind JSON package,
and use POJOs instead.
Add main() for testing
2018-11-20 11:05:46 +00:00
zzz
3923db0677 Modify MaxMind-DB-Reader-java
to remove the dependency on the large com.fasterxml.jackson.databind JSON package,
and use POJOs instead.
2018-11-20 11:03:47 +00:00
zzz
98de1ae404 This is GeoIP2-java release 2.12.0 2018-04-11
retrieved from <a href="https://github.com/maxmind/GeoIP2-java">github</a>.
For reading MaxMind GeoLite2 database files.
Contains only the DatabaseReader class from that package.
Unmodified as a baseline for future merges.
Does not compile.
To be heavily modified to remove the dependency on the large
com.fasterxml.jackson.databind JSON package,
and use POJOs instead, see following revs.
Apache 2.0 license.
2018-11-20 10:59:43 +00:00
zzz
76921b1e3e This is MaxMind-DB-Reader-java release 1.2.2 2017-02-17
retrieved from <a href="https://github.com/maxmind/MaxMind-DB-Reader-java">github</a>.
For reading MaxMind GeoLite2 database files.
Unmodified as a baseline for future merges.
Does not compile.
To be heavily modified to remove the dependency on the large
com.fasterxml.jackson.databind JSON package,
and use POJOs instead, see following revs.
Apache 2.0 license.
2018-11-20 10:57:33 +00:00
zzz
97e7a98aed JSON javadoc fixes 2018-11-19 14:59:14 +00:00
zzz
d263e42e1e Debian: Add libjson-simple-java dependency 2018-11-19 14:58:20 +00:00
zzz
54184f2889 Util: Switch users of net.minidev.json to com.json.simple
Tested with bundled 1.1.1 and Debian/Ubuntu 2.3.0
2018-11-19 14:48:21 +00:00
zzz
af9ce6d173 Change json lib from net.minidev.json to com.json.simple
because libjson-simple-java is in Debian (jessie+) and Ubuntu (trusty+).
Version 1.1.1 (Feb. 2012) from:
https://github.com/cliftonlabs/json-simple
https://github.com/fangyidong/json-simple/releases
License: Apache 2 (same as minidev)
Release info:
https://cliftonlabs.github.io/json-simple/
Current version 2.3.0 (in buster/sid/bionic+) is compatible.
The 3.x branch is incompatible.

No known external users of minidev (JSON_SMART) which was added in April 2018
(0.9.35) for DoH and the eventual bundling of i2pcontrol.
The i2pcontrol plugin was switched from json-simple to minidev in early 2018,
but it bundles the minidev source. When we bundle, we can switch it back.

Does not compile; see checkins to follow.
2018-11-19 14:44:31 +00:00
zzz
a1baf856f9 Wizard: Fix cancel test button 2018-11-18 16:13:47 +00:00
zzz
13d80e604d Wizard: Ajax fixes for IE (thx zlatinb) (summary bar also)
Form notices on results panel
Hide results if skipped
2018-11-18 13:43:18 +00:00
zzz
09ea40ce8e bump -5 2018-11-17 12:33:00 +00:00
zzz
bbccb476c0 NTCP2 unused code 2018-11-17 10:26:59 +00:00
zzz
0526d6fd15 add bw test to commandline 2018-11-17 10:25:20 +00:00
zzz
c5bd0bd079 NDT: Add support for test over SSL
error handling
log tweaks
2018-11-17 10:19:55 +00:00
zzz
6963d1f746 NDT: Fix NPE caused by last checkin 2018-11-16 21:36:46 +00:00
zzz
a5c38ba6e3 NDT: Remove Swing call 2018-11-16 19:47:36 +00:00
zzz
bfb6eba90c NDT: Thread tweaks 2018-11-16 19:43:11 +00:00
zzz
c07f68e622 NDT: Fix locale, spoof OS, fix log init 2018-11-16 19:27:57 +00:00
zzz
9b9810ea1e MLab: Switch to name server that supports SSL
swingemu cleanups
2018-11-16 17:12:32 +00:00
zzz
9a254aec55 NDT: Restore logging removed in last rev 2018-11-16 15:08:20 +00:00
zzz
aa11211e5e Wizard: Improve ajax
Drop unused test wrapper
Enable first run detection
Spelling fix
2018-11-16 14:34:11 +00:00
zzz
f1e9bf8222 bump -4 2018-11-15 19:45:21 +00:00
zzz
812baf8bd9 NDT log tweaks 2018-11-15 19:39:08 +00:00
zzz
5fe2019897 basic XHR 2018-11-15 19:05:40 +00:00
zzz
aebf7735fe NDT: remove unused user-agent code 2018-11-15 18:04:18 +00:00
zzz
bdbadcd8af Wizard: Warn if trying to start NDT twice 2018-11-15 17:53:50 +00:00
zzz
54a1609760 Wizard: Signal bwlimiter after config change
Remove debug log in form handler
2018-11-15 17:41:57 +00:00
zzz
0369d321d3 Wizard: Hook test results to form
More fixes and cleanups
2018-11-15 16:45:21 +00:00
zzz
62c712c462 Wizard: More test results 2018-11-15 15:07:17 +00:00
zzz
dc343b05a2 MLab/NDT: Hook test to wizard
Make helper the session scope, not handler
Reduce whitespace in formhandler.jsi
Notes on why FormHandler can't be session scope
Ajax still TODO
2018-11-15 14:24:46 +00:00
zzz
6462e2a292 MLab/NDT: Prep for connecting to wizard, fixes, cleanups 2018-11-14 14:48:10 +00:00
zzz
a35ad5fc57 javadocs 2018-11-13 19:37:38 +00:00
zzz
d95c284d3e MLab/NDT: static instance, log fixes, cleanups 2018-11-13 19:20:10 +00:00
zzz
84c0aa4072 javadoc 2018-11-13 19:18:42 +00:00
zzz
cec94e934a Console: Remove some config items from home page 2018-11-13 18:01:26 +00:00
zzz
b695242daf Router: LS2 handling for proposal 123 2018-11-13 18:00:05 +00:00
zzz
ddfc7c05ef Data: support non-string values in DataHelper.toString(Map) 2018-11-13 17:53:33 +00:00
zzz
9377b57c9e ElG minor cleanup 2018-11-13 17:51:52 +00:00
zzz
2bfbcf1ae9 jsi whitespace removal 2018-11-13 17:48:58 +00:00
zzz
f8f6375738 New install setup wizard
Work in progress, run on first install disabled.
Language and bw settings should work,
other panes todo.
2018-11-13 17:46:18 +00:00
zzz
c074467163 MLabRunner, adapted from Vuze/BiglyBT MLabPlugin.java
Github rev e927dca, Aug. 18, 2018.
From: https://github.com/BiglySoftware/BiglyBT-plugin-mlab
License: GPLv2
Work in progress, command line test works,
not hooked up to console yet, awaiting wizard
Build changes to copy in translation files,
and put the javadocs in the right place.
2018-11-13 17:26:38 +00:00
zzz
92787f8fcc swingemu fix to compile Tcpbw100 from 3.7.0.2 2018-11-13 17:21:54 +00:00
zzz
71d8f0e4d4 Vuze/BiglyBT Swing emulation layer for NDT Applet.
This is a simple shim to allow running the NDT Applet code
with minimal modifications.
From BiglyBT MLab plugin:
Github rev e927dca, Aug. 18, 2018.
From https://github.com/BiglySoftware/BiglyBT-plugin-mlab
This is for Tcpbw100 from NDT 3.6.2b;
not sufficient to compile Tcpbw100 from 3.7.0.2,
changes to follow.
License: GPLv2.
2018-11-13 17:20:33 +00:00
zzz
e20401373c NDT changes adapted from Vuze/BiglyBT, and changes for I2P.
Vuze/Bigly is based on NDT 3.6.2b, so their changes are
manually merged here.
This rev does not compile, requires swingemu package to follow.
Changes:
- Add external start hook to Tcpbw100 from BiglyBT
- Replace all Swing/AWT classes with emulations from BiglyBT
  (included in next checkin)
- Leave classes in edu.internet2.ndt package rather than
  moving to com.vuze.plugins.mlab heirarchy as Vuze/BiglyBT did
- Change IPv6 support setting to use I2P class for detection
- Change in-progress field to an AtomicBoolean
- Change from System to I2P logging
- Change JSON library package
- Comment out some applet code
- Javadoc fixes
2018-11-13 17:08:56 +00:00
zzz
6f7881c7ea Web100 Network Diagnostic Tool (NDT) Java Applet
Version 3.7.0.2 (May 20, 2015)
From: https://github.com/ndt-project/ndt/releases
Unmodified, as baseline for future merges.
Will not compile, changes adapted from BiglyBT to follow.
Copyright 2003 University of Chicago.
3-clause license with requirement that:
  Modified copies and works based on the Software must carry prominent
  notices stating that you changed specified portions of the Software.
See LICENSE.txt and licenses/LICENSE-NDT.txt
2018-11-13 16:58:05 +00:00
meeh
e326011a93 merge of '917225cb79561b9c536091f9c0790633ebbca610'
and 'c9243853a4211ebe92d964f7aa6ba57e624d6ab8'
2018-10-14 01:46:17 +00:00
zzz
e9ec043bf4 Data: Encrypted LS2, other LS2 changes 2018-10-13 14:36:39 +00:00
zzz
e391992251 Data: MetaLeaseSet2 data structure, LS2 test enhancements 2018-10-13 12:46:45 +00:00
zzz
02f5733eee Data: Prop 123 Meta Lease 2018-10-13 11:40:14 +00:00
zzz
a9f957504e Data: Lease2 and LeaseSet2 data structures, prop. 123 store types 2018-10-13 10:49:50 +00:00
zzz
f0b3815767 Data: Prep Lease and LeaseSet for subclassing 2018-10-13 10:41:16 +00:00
zzz
ee57bd7363 Data: Add encryption types for PublicKey, PrivateKey 2018-10-13 10:39:20 +00:00
zzz
4c970fa0aa Data: SPK log tweaks 2018-10-13 10:35:30 +00:00
zzz
0a99784221 Build: Add javac.classpath to junit.compileTest targets (ticket #2333) 2018-10-13 09:32:51 +00:00
meeh
eed8011725 OSX Launcher: dmg create script update 2018-10-13 04:06:44 +00:00
meeh
f8fb4a66dd OSX Launcher: Remove restart button 2018-10-13 04:06:02 +00:00
meeh
4f8af55378 OSX Launcher: Storyboard update 2018-10-13 04:05:38 +00:00
meeh
530470972f OSX Launcher: general cleanup, responsibility delegation, and fixes 2018-10-13 03:54:01 +00:00
meeh
a9bf9e0657 OSX Launcher: make deployer an property so it's not deleted in mid-extract by GC. 2018-10-13 03:52:40 +00:00
meeh
e2d22645e1 OSX Launcher:
* UI Bugfixes/features
    * restart might work
    * open console button should work
    * cleanup
2018-10-13 03:51:22 +00:00
meeh
5f077891ae OSX Launcher: Storyboard update 2018-10-13 03:47:28 +00:00
meeh
1a00f73191 OSX Launcher: Extended start/stop/load/unload to be able to set terminationHandler for more reliable execution. 2018-10-12 20:52:24 +00:00
meeh
d8cfe21e92 OSX Launcher: make some string functions inline 2018-10-12 20:07:59 +00:00
meeh
ee9976c288 OSX Launcher: Xcode UI elements update. 2018-10-12 20:07:36 +00:00
meeh
10707c6d71 merge of '1f8e31dab7ed66ddd8f332fca5784b4934d0c9b0'
and '4197dba37e7c738c7b1125b3e407a7bc0b2c972a'
2018-10-11 17:04:49 +00:00
meeh
8e988c39e9 OSX Launcher: Updated build instructions in readme 2018-10-11 17:03:11 +00:00
meeh
e3ab9f8e91 OSX Launcher: Swift GUI code updates, most related to the new launch method. 2018-10-11 17:02:42 +00:00
meeh
96d31995e1 OSX Launcher: cleanup and restructuring the main swift file 2018-10-11 17:01:21 +00:00
meeh
3988a8645d OSX Launcher: major updates to the glue between 'backend' and GUI. Implemented the use of the new LaunchAgent classes 2018-10-11 16:59:59 +00:00
meeh
b25dec12d1 OSX Launcher: some changes to the Swift<->Objective-C bridge 2018-10-11 16:58:20 +00:00
meeh
f57f8c6083 Some more xcode metadata files 2018-10-11 16:56:26 +00:00
meeh
2862be564e XCode metadata files update 2018-10-11 16:55:36 +00:00
meeh
45b4f426a8 OSX Launcher: Big rewrite of swift code where it now has the capability of creating services.
The router management has been much easier with this approach as it uses launchd to do the dirty work.
This code also uses java_home as a wrapper instead of locating the java binary by itself. This also contribute to the improvements.
2018-10-11 16:55:07 +00:00
meeh
51cbd8ef87 Dropping unused swift class 2018-10-11 16:49:51 +00:00
meeh
8b2c3de795 OSX Launcher: Cleaning up DetectJava.swift 2018-10-11 16:49:19 +00:00
meeh
969bc2dee3 OSX Launcher: String extensions update 2018-10-11 16:48:10 +00:00
zzz
77e539a73c Docs: Add maven doc from str4d via mattermost
Update dependencies doc
2018-10-11 14:33:23 +00:00
zzz
2de36ee343 Console: Remove static Server ref, hang off RCR 2018-10-11 13:10:33 +00:00
meeh
7dbf568212 OSX Launcher: Refactor deployment code to own file, + code cleanups. 2018-10-11 11:55:05 +00:00
meeh
7e9d1939b1 OSX Launcher: Storyboard update 2018-10-11 11:51:55 +00:00
meeh
48877079ca OSX Launcher: Log all events for debugging 2018-10-11 11:50:00 +00:00
zzz
e68182a157 Build: Provide option to prevent Class-Path in manifests (ticket #2317) 2018-10-10 12:30:34 +00:00
zzz
06914f9fd4 Sybil: Take HTML out of reason string for easier parsing and storage 2018-10-09 16:56:50 +00:00
zzz
8332385f05 Sybil: More prep and refactor for background analysis
Put dest name in too-close reasons
2018-10-09 16:37:29 +00:00
zzz
19b1b3cec4 Sybil: Prep for background analysis
sort threat points
consolidate strings
2018-10-09 14:55:13 +00:00
zzz
bdd7c35ab3 Console: Remove static StatSummarizer ref, hang off ClientAppManager 2018-10-08 19:31:54 +00:00
zzz
184b6179e5 i2psnark: Sync field access (findbugs) 2018-10-08 14:24:46 +00:00
zzz
6fccfc990a Use Double.compare() in comparators (findbugs) 2018-10-08 13:34:15 +00:00
zzz
524c375944 Data: Drop long-deprecated and unused boolean methods and related tests 2018-10-08 12:43:58 +00:00
zzz
5041bb8531 netdb class cleanup 2018-10-08 12:13:24 +00:00
zzz
7dfee5f0ab NTCP2 log tweak 2018-10-07 19:50:59 +00:00
zzz
e3d456c733 Debian: Don't override dh_builddeb (ticket #2329) 2018-10-07 15:54:12 +00:00
zzz
e2a41b7748 Console: Sort RAs in Sybil tool 2018-10-07 14:52:24 +00:00
zzz
477fa9ef3a Build: Fix build config with-libtomcat8-java but not with-libjetty9-java,
by copying required jetty jar to jetty-apache-jsp.jar
2018-10-07 14:29:47 +00:00
zzz
0cd67acd19 Console: /netdb fixes (ticket #2326):
- 'O' cap search won't include P/X
- Fix highlighted tab for transport search
- Use POST instead of GET
2018-10-06 22:59:58 +00:00
zzz
aafccc0132 Console: Fix SSU sort links broken in last checkin 2018-10-06 17:40:05 +00:00
zzz
ff1e53a0e3 Console: Fix bw cap display for P/X on /tunnels 2018-10-06 17:09:14 +00:00
zzz
b8d33f7426 Console: Tab /peers, fix html errors 2018-10-06 16:50:32 +00:00
zzz
8dc3163c73 flip sections on /confighome 2018-10-06 13:33:19 +00:00
zzz
960636c6bf Console: Sort addresses in RIs, remove note about O cap 2018-10-06 13:25:22 +00:00
zzz
e528775768 debian changelogs 2018-10-05 18:41:48 +00:00
zzz
52739165a1 0.9.37 2018-10-04 10:01:44 +00:00
zzz
eb1d848372 bump for review 2018-10-01 17:41:20 +00:00
zzz
2a9c39ca6e missed one 2018-10-01 17:04:26 +00:00
zzz
b84b298ec8 pull translations from tx 2018-10-01 16:55:26 +00:00
meeh
e59dd3bcec Mac OSX Launcher: LICENSE file for the sbt bash script. 2018-09-30 13:55:06 +00:00
meeh
d6fc0adb56 Mac OSX Launcher: Removed dmgconfig.py, added public domain to sharedqueue.h and updated xcode for the dmgconfig.py removal. 2018-09-30 13:42:32 +00:00
meeh
5041883d5a Mac OSX Launcher: Update readme regarding Oracle's downlad url. 2018-09-30 11:37:12 +00:00
meeh
5ed701dff3 Mac OSX Launcher: updates in logging, remove timestamp from Objc's MLog 2018-09-30 11:34:20 +00:00
meeh
410f9df4e4 Mac OSX Launcher: The launcher will now write the pid of the router to a file like the old wrapper did. 2018-09-30 11:29:21 +00:00
meeh
b5497ef72e Mac OSX Launcher: Cancel stream that can cause high cpu load on router stop. 2018-09-30 11:02:28 +00:00
meeh
2233f7f47b Mac OSX Launcher:
* Update readme about event manager
  * RouterTask can now detect a running router by scanning processes&arguments for i2p.jar
  * The logger will log to OSX's default: ~/Library/Logs/I2P/[whatever].log
2018-09-30 09:40:43 +00:00
meeh
36b758f2c0 Mac OSX Launcher: Removing unused/change-in-plans files 2018-09-30 09:37:51 +00:00
meeh
ae0d420f5f Mac OSX Launcher:
* Added script to check for latest java via xcode
  * Updated xcode project metadata files
  * Update dmg create script
  * Make xcode write version.h under build
  * Added template for version.h
2018-09-30 09:35:28 +00:00
meeh
b40b987c0f Mac OSX Launcher:
* Fixed issue with >> and compilers in C++ in subprocess.hpp
  * Added queue for logger
  * Misc
2018-09-30 09:32:49 +00:00
meeh
e8d371ed9b Mac OSX Launcher: C api of the logger to become available for Swift/Objective-C 2018-09-30 09:31:29 +00:00
meeh
5a0017a8fe Mac OSX Launcher: Adding a logger library I wrote a good while ago, refactored it to work with the launcher. 2018-09-30 09:30:39 +00:00
meeh
751f15c1b1 Update .mtn-ignore for osx stuff 2018-09-30 09:28:52 +00:00
zzz
d1b2a4e51c apparmor update 2018-09-29 19:44:23 +00:00
zzz
6ef6b3b705 new geoipv6 data, bump builddate 2018-09-29 17:20:57 +00:00
slumlord
c069f76324 Add "clearer" div to Hidden Services Of Interest section in /home so that nested floating divs are displayed properly 2018-09-29 08:48:31 +00:00
slumlord
9a11165bfc propagate from branch 'i2p.i2p' (head effa099b40ff593227c59707a33922176dc775b1)
to branch 'i2p.i2p.slumlord' (head 5ddcc0dd19779b78356459bd074f75943d5d42d1)
2018-09-29 08:40:20 +00:00
zzz
3a5f020dac SSL Wizard: Don't put public IP in SAN 2018-09-27 15:05:57 +00:00
zzz
d67d501b28 Data: Don't corrupt hidden RI with addresses 2018-09-27 14:38:18 +00:00
zzz
a69aa15acd drop zerobin 2018-09-27 14:12:30 +00:00
zzz
c391dacf7d sybil tweaks 2018-09-27 14:07:38 +00:00
zzz
69f380f4a1 flip /home sections 2018-09-26 22:59:55 +00:00
meeh
22a0f396e6 Mac OS X Launcher:
* Enabled Apple's "Hardened Runtime", however unsecure memory had to be allowed to spawn java etc.
  * Updated docs about Event Manager code
  * Make the launcher handle cases where extract is incomplete or invalid
  * Bugfixes as always
2018-09-26 20:42:58 +00:00
zzz
d27000ec07 Crypto: Avoid java-to-i2p ECDSA privkey conversion when generating CRL,
failing on Android for unknown reasons (ticket #2296)
2018-09-26 15:19:14 +00:00
zzz
b82ace8a84 Router: Don't add 'O' cap for P/X anymore 2018-09-26 14:20:11 +00:00
zzz
b7ff82eb82 IRC: Make inbound whitelist static 2018-09-26 14:16:05 +00:00
zzz
f7ae675201 cleanup 2018-09-26 14:12:05 +00:00
zzz
39aa2c597e Utils: Enhance exception message for ticket #2296 2018-09-26 14:04:36 +00:00
zzz
34f0d7d7b3 Build: Compile jsps in-order for reproducibility (ticket #2279) 2018-09-24 15:52:42 +00:00
zzz
e59d7a821b Plugins: Blacklist neodatis and seedless for Java 9+ (ticket #2295) 2018-09-23 15:11:16 +00:00
meeh
7a72049e28 Mac OS X Launcher:
* Bugfixes as always
  * Added Sparkle (native updater, https://sparkle-project.org/ )
  * The launcher will now extract and overwrite older versions if found
  * Rewrite of the java extraction part (to enable overwrite)
  * Move more functionality to use EventManager as it works quite well
  * Added check for updates menu item
2018-09-23 03:33:29 +00:00
meeh
3b38f5a161 Mac OS X Launcher:
* In general bugfixes
  * Introduced event manager for better control flow
  * Splitted RouterStatusView to own file
  * Added shell script to setup and produce dmg file
2018-09-22 22:13:40 +00:00
zzz
829eb665e9 NTCP: Fix handling of multiple connections,
change termination code for expired RI, log tweaks
2018-09-22 12:13:51 +00:00
zzz
4369b7d122 merge of 'dba1ad61c390f95055923ae1fb35e60552f617c6'
and 'f84ff8b356783cf12619b83a8104e55fe76a7411'
2018-09-22 12:11:43 +00:00
meeh
70fa2dae0a Mac OS X Launcher: Let version detection etc happen even a router is already started. 2018-09-20 03:27:37 +00:00
meeh
85ebb2f847 Mac OS X Launcher: Removed unused header file. 2018-09-20 03:22:41 +00:00
meeh
e8decff5cd Mac OS X Launcher: more cleanup and some bugfixes. 2018-09-20 03:20:39 +00:00
meeh
3c0a8cf4ab Mac OSX Launcher: A lot of bugfixes, refactoring and cleanup. 2018-09-20 02:38:44 +00:00
meeh
eb81cadac0 OSX Launcher: Removing script for old build system 2018-09-19 19:12:26 +00:00
meeh
0f8a61803f Remove license for now unused library. 2018-09-19 17:01:12 +00:00
meeh
e046418f8f Cleaning up the code base, remove dead code and failed attempts. 2018-09-19 17:00:17 +00:00
meeh
802115e813 Updating .mtn-ignore file 2018-09-19 16:13:05 +00:00
meeh
9b958e4427 Moving replace function to strutil.hpp 2018-09-19 16:03:39 +00:00
slumlord
46ac008775 #2298 - Improve formatting to make translation-related activity easier; More details on trac 2018-09-19 10:37:37 +00:00
meeh
281c5f579f Bugfixes, improvements, more error handling and stability to the osx launcher. 2018-09-19 00:37:16 +00:00
meeh
01a05f7600 Adding license for forked subprocess code in swift.
MIT, ref. https://github.com/marcoconti83/morione
2018-09-19 00:14:25 +00:00
meeh
f76874ac19 Adding XCode workspace & Xcode project, and some files missing from last commit.
Please note that Xcode project embedds the packing script (meaning it runs "ant" - zip files, and moves it to bundle)
2018-09-18 15:39:32 +00:00
meeh
7615b9236b Adding all new code, removed a lot obsolete code and fixed import paths etc.
Mac OS X launcher:
* UI built on Swift
  * Why?
    * Apple seems to on purpose make it harder to get into Objective-C these days
    * Swift is compiled to native code, but has easiness of Javascript in programming
    * Perfect for the OS X UI, many guides & tutorials as well
* "Backend" in Objective-C++ / C++14
  * Why?
    * Originally written in Objective-C / C++14 with C++17 backports
    * Only for backend because of the time the development takes
    *

Short summary of features:

* Java
  * It can detect java from:
    * JAVA_HOME environment variable
    * "Internet Plug-Ins" Apple stuff
    * By the /usr/libexec/java_home binary helper
  * It can unpack a new version of I2P
    * Unpacks to ~/Library/I2P
    * Can check currently unpacked version in ~/Library/I2P via i2p.jar's "net.i2p.CoreVersion"

  * User Interface (a popover, see https://youtu.be/k8L3lQ5rUq0 for example of this concept)
    * Router control tab view
      * It can start the router
      * It can stop the router
      * It can detect already running router, then avoid fireing up one
      * It can show basic information about the router state & version
    * Log view tab (not yet done)
  * While left-click triggers popover, right-click draws a minimal context menu
2018-09-18 15:36:38 +00:00
meeh
1bddf5527a Commiting XCode's image/resources library alone since it's massive with blobs. 2018-09-18 15:20:21 +00:00
meeh
beede9505e Preparing for XCode project. Removing now obsolete files. 2018-09-18 15:19:23 +00:00
zzz
b74abbe4de Tomcat 8.5.34 2018-09-16 20:37:47 +00:00
zzz
6b53a4fac4 Build: Fix hang with Tomcat 8.5.33+ (ticket #2307) 2018-09-16 11:29:03 +00:00
slumlord
be4c1afe13 propagate from branch 'i2p.i2p' (head 056bc63e77d33f38fb1644b84f9071693ff754a3)
to branch 'i2p.i2p.slumlord' (head 95a150a83187020444206ec94d48c4e4789b7174)
2018-08-31 01:56:37 +00:00
slumlord
4ead982831 Fix port forwarding line in readme.html 2018-08-31 01:54:30 +00:00
slumlord
4011680fad propagate from branch 'i2p.i2p' (head f7b28892c564f2b360f9f9dc8a8ad11c760b347a)
to branch 'i2p.i2p.slumlord' (head 0eab0dc27f9269e2791700882ad4b289d566348a)
2018-08-27 13:13:42 +00:00
zzz
48c787ba8d Debian: Prevent dup version (ticket #2300) 2018-08-27 11:34:48 +00:00
slumlord
c9002b327b #2293 - Use CachedIteratorCollection in PeerState 2018-08-27 06:36:49 +00:00
slumlord
873087441a Use CachedIteratorCollection in PeerState 2018-08-27 06:36:05 +00:00
slumlord
f6c45355a4 propagate from branch 'i2p.i2p' (head fea8e3400c114ad820bf3f0eb7d18336b85027cb)
to branch 'i2p.i2p.slumlord' (head 472429fc9d4d273e0d05de5ae0c075c5ebfca45f)
2018-08-27 06:30:31 +00:00
slumlord
92cc66ecb2 Update RouterVersion.java to match i2p.i2p to allow for propagation from i2p.i2p 2018-08-27 06:25:51 +00:00
slumlord
773676075c Revert PeerState.java temporarily to allow for propagation from i2p.i2p 2018-08-27 06:20:40 +00:00
zzz
e64ad7ce57 More findbugs all over 2018-08-26 15:13:49 +00:00
zzz
1f92232253 Findbugs all over 2018-08-26 13:50:40 +00:00
zzz
db54edc36d NTCP2: Publish outbound address after transition to firewalled
Fix exception thrower
2018-08-26 12:05:49 +00:00
zzz
3adbea9c76 Better message on su3 certificate errors 2018-08-25 22:26:47 +00:00
zzz
483f043d3c Bettor error message on covariant fail 2018-08-25 18:22:55 +00:00
zzz
819985f3b4 lint 2018-08-25 17:56:30 +00:00
zzz
21fbcb8749 NTCP2: Enable by default 2018-08-25 17:35:29 +00:00
zzz
4a03b6fcb0 i2psnark: Better comment deduping, fixes rating average 2018-08-25 16:35:41 +00:00
zzz
57ddc8ea4f conversion cleanup 2018-08-25 14:29:32 +00:00
zzz
c3881a811b fix deprecations 2018-08-25 13:26:28 +00:00
zzz
ff551b19fb debian doc update 2018-08-23 22:16:50 +00:00
zzz
a45f5374e4 Ubuntu 0.9.36 2018-08-23 22:10:04 +00:00
zzz
1453527382 NTCP2 remove unused code 2018-08-23 15:27:05 +00:00
zzz
cc2056d4cf NTCP2 code consolidation, minor changes 2018-08-23 15:25:45 +00:00
zzz
6cf84ac5a3 log tweak 2018-08-23 15:22:30 +00:00
zzz
e243e0ddba streaming minor tweaks 2018-08-23 15:20:29 +00:00
zzz
fddaa47ded whitespace fix 2018-08-23 15:18:54 +00:00
zzz
658faf9dcf 0.9.36 2018-08-22 20:07:41 +00:00
zzz
68feb080e7 Jetty 9.2.25.v20180606 2018-08-20 13:18:29 +00:00
zzz
f4cab090cd man fixes 2018-08-19 21:41:05 +00:00
zzz
d69f078d8d new man translations 2018-08-19 21:37:19 +00:00
zzz
f2e00ca130 More translation updates
GeoIPv6 update 2018-08-16 from Maxmind
2018-08-19 21:25:46 +00:00
zzz
ea3ce805e4 log typo 2018-08-19 21:02:20 +00:00
zzz
96f7c15e6e pull from tx 2018-08-19 21:00:22 +00:00
zzz
a846271cd4 NTCP2: Catch bad IV exception 2018-08-19 18:56:59 +00:00
meeh
da476be75e Fixed neither's license with including LoopPerfect's
license line.
2018-08-19 17:17:42 +00:00
slumlord
a5830f0203 propagate from branch 'i2p.i2p' (head ac85a7ea91b76b247e7987f5baed14167c5a0661)
to branch 'i2p.i2p.slumlord' (head 5ee52fb5eff362cca2a2bb3a6130aecc2543e734)
2018-08-19 13:51:36 +00:00
zzz
a01bfff974 merge of '412307149f63744814cd43d5df85bc227b8e4667'
and 'cd23f58885590026a755c32f8f2c2f513e22e21c'
2018-08-18 16:18:42 +00:00
meeh
8b9e5de9a7 merge of '3985486d761603f3e27f0f9e50fe3ae6d6a022be'
and '7acf152f554c78474ef071ac74ceb6a4889c600b'
2018-08-18 15:49:10 +00:00
meeh
aef68eb93e Remove duplicated file. 2018-08-18 15:49:05 +00:00
meeh
4a5708ab78 merge of 'e44534030f8f27481da60564e03f4b097f032c89'
and 'eea0aed1232ed304fa6ffeaeee28d9399bf3efdc'
2018-08-18 15:48:16 +00:00
meeh
7cf79a3a20 Adding LICENSE file for Boost and MIT.
This licenses the files lying under the path
launchers/macosx/obj-cpp/include in this repository.

launchers/macosx/obj-cpp/include/neither is MIT, while the
rest unless spesified in the header, is Boost.

C++17 variant, eggs implementation is licensed under Boost,
original source can be found at http://eggs-cpp.github.io/variant/
forked at: f801e971d054341430cb91d79aa0bb4d0bf24330

C++ Neither is licensed under MIT, original source can be found at
https://github.com/LoopPerfect/neither
forked at: a2bbaa25d62c538fb044a6eda5254e7a068e4ff7

C++ Optional implementation is licensed under Boost, original source
found at https://github.com/akrzemi1/Optional
forked at: f6249e7fdcb80131c390a083f1621d96023e72e9
2018-08-18 15:47:48 +00:00
meeh
8bebda2e35 Remove duplicated file. 2018-08-18 15:47:35 +00:00
slumlord
42fd4c645c Revert changes checked-in in revision ec64be9e9faf415091bda0fe3567c6460310f7ad as they were not intended for this branch 2018-08-17 11:16:19 +00:00
slumlord
211533f554 Update PeerState to use CachedIteratorCollection as propagation from i2p.i2p appears to have wiped out changes 2018-08-17 10:05:17 +00:00
slumlord
11945c823e propagate from branch 'i2p.i2p' (head ec664ddfcb1f460b67cfcb0a5be1d162bb361b5a)
to branch 'i2p.i2p.slumlord' (head c521652f676d8c99cc31916977229cca561dc31b)
2018-08-17 09:23:45 +00:00
slumlord
26189704f3 Re-add file 2018-08-17 08:37:41 +00:00
slumlord
5b114f4bf3 Removing files temporarily to allow for propagation from i2p.i2p branch 2018-08-17 08:37:03 +00:00
zzz
c455f15b2a i2ptunnel: Change read timeout defaults now that streaming read timeout works 2018-08-16 18:39:07 +00:00
zzz
30fefa44ec Console: Format part. tunnel rate
Make table headers consistent
2018-08-13 17:38:57 +00:00
slumlord
e310a6ab31 Add CachedIteratorCollectionTest 2018-08-13 08:38:24 +00:00
slumlord
a40ff5f528 Add CachedIteratorCollectionTest - junit tests for CachedIteratorCollection 2018-08-13 08:33:45 +00:00
slumlord
a7e31f1f2b propagate from branch 'i2p.i2p' (head 28e7fe42a73f3806f0d5f805801039e9b6ba66d3)
to branch 'i2p.i2p.slumlord' (head d33d35ee38f522ea71205b041f00420405684dbf)
2018-08-11 06:34:30 +00:00
zzz
1c73be515a move return inside sync 2018-08-10 16:36:33 +00:00
zzz
8dbc11566b log level tweaks 2018-08-10 16:35:03 +00:00
slumlord
8408e9fe22 propagate from branch 'i2p.i2p' (head e6dfc137396019d82f0f6f08216b5b2496366f1c)
to branch 'i2p.i2p.slumlord' (head 8944540a640826823268268cfcc018be8aa1bc3d)
2018-08-09 09:15:21 +00:00
zzz
62151ef525 poupdate-source 2018-08-08 18:55:22 +00:00
zzz
f855421901 tx resource for readme 2018-08-08 18:46:43 +00:00
slumlord
61d2e3c208 propagate from branch 'i2p.i2p' (head 9ad2c13f2722c6d9b6387b333e803df6f58a02c8)
to branch 'i2p.i2p.slumlord' (head ec6542c798755f65bc61caf00100a9d49b7d61a0)
2018-08-08 12:01:54 +00:00
zzz
9e237b5086 new hosts 2018-08-07 20:58:57 +00:00
slumlord
f97ec8820c CachedIteratorCollection - Fix add() function 2018-08-07 12:04:49 +00:00
slumlord
f9d5d48a4d Clean up code 2018-08-07 12:04:31 +00:00
slumlord
733d3496a9 Append "-sl" to version string 2018-08-07 10:15:27 +00:00
slumlord
5a6ee17f3c CachedIteratorCollection - Fix bug in add() function
Add comments for remove() function
2018-08-07 08:28:16 +00:00
slumlord
177ef573ee Update javadocs for CachedIteratorCollection 2018-08-06 15:14:15 +00:00
slumlord
57fee62557 Fix PeerState 2018-08-06 15:13:41 +00:00
slumlord
7084c86e76 Update CachedIteratorCollection javadocs 2018-08-06 15:08:41 +00:00
slumlord
68482cab43 propagate from branch 'i2p.i2p' (head 561efd6f3e61619f76be7effbd775178a116007b)
to branch 'i2p.i2p.slumlord' (head 11d4aac5f949cac61aaf08c22e0c2a862f09c91a)
2018-08-06 14:52:03 +00:00
slumlord
fc22d0fcbc merge of '5ceba68eb23bd6229800383e7f9e917bff86b83f'
and '9b8562d09e23badb58dadcedb61bb9a6fa446e6a'
2018-08-06 12:07:25 +00:00
slumlord
da5c922c40 Rename CachedIteratorAbstractCollection.java to CachedIteratorCollection.java 2018-08-06 12:05:51 +00:00
zzz
aaebbdedcc Debian: Remove old flags dir so symlink gets created 2018-08-06 11:33:59 +00:00
slumlord
d2b32bc754 PeerState patched for CachedIteratorAbstractCollection; With branch 'i2p.i2p.slumlord' this time 2018-08-06 10:08:44 +00:00
slumlord
4aff615687 Revert changes to PeerState and .idea/ folder in previous commit 2018-08-06 09:47:32 +00:00
slumlord
0b3abb3b63 Add CachedIteratorAbstractCollection
Update PeerState.java to use CachedIteratorAbstract
Add some debugging lines to determine cause(s) of higher udp.sendFailed/sendAggressiveFailed stats
2018-08-06 08:54:44 +00:00
zzz
775188a36c I2NP: Fix DI test 2018-08-04 16:31:10 +00:00
zzz
21fe962abd I2NP: Remove unused OutputStream methods 2018-08-04 15:23:36 +00:00
zzz
9b3eb8d2c3 I2NP: Change DeliveryInstructions internal flags storage from long to int 2018-08-04 15:16:21 +00:00
zzz
a5a5f7dbde I2NP: Don't call toLong() for 1 byte 2018-08-04 14:50:33 +00:00
zzz
30f25de49b I2NP: Remove unused InputStream parsing methods 2018-08-04 14:35:00 +00:00
zzz
2cc362ca7b javadoc fix 2018-08-04 14:33:57 +00:00
zzz
f1df49606d Data: Check sooner for unknown sig type;
minor efficiency improvements in parsing
2018-08-04 13:41:01 +00:00
zzz
c0be83fe08 readme edits 2018-08-03 23:10:38 +00:00
zzz
0b2ef3da13 NTCP2: Fix termination handling
log tweaks
2018-08-03 20:14:46 +00:00
zzz
526aadb559 NTCP2: Fix padding calculation for small frames 2018-08-02 21:08:20 +00:00
zzz
8d629de23d readme edits 2018-08-02 20:50:18 +00:00
zzz
8fb7bd264f NTCP2: Remove debug code 2018-08-02 11:48:55 +00:00
zzz
2e85c2387c merge of '2854c97dc4c2cef6d9bd92f80032b60ad86ab030'
and 'df5322d83c1545129c9ed8f3e2dc5378ffb1b4a3'
2018-08-02 10:56:39 +00:00
zzz
1b6c002883 NTCP2: Send termination on idle timeout
Use timer to delay close after sending termination
Prevent sending more data after termination
2018-08-02 10:56:14 +00:00
slumlord
7121e3e52e #2239 - Updating readme.html, work in progress. 2018-08-01 11:44:33 +00:00
zzz
726d2f4752 ngettext 2018-07-31 14:27:18 +00:00
zzz
75d86727ec SSU: Pull call out of loop for efficiency 2018-07-31 14:26:03 +00:00
zzz
5c3e408772 i2psnark: Don't disconnect seeds immediately if comments enabled (ticket #2288)
Implement variable timeout
Hardcode handshake bytes
Log tweaks
2018-07-31 14:13:33 +00:00
zzz
a51d260a78 Streaming: More efficient copying in MessageInputStream
Log tweaks
2018-07-29 13:30:02 +00:00
zzz
b5ed39f10d Streaming: Throw exception on read timeout (ticket #2292)
Log tweaks
2018-07-28 21:44:56 +00:00
zzz
f12dbba3d6 SusiMail: Catch ISE in get/setAttribute() (ticket #1529) 2018-07-28 19:48:22 +00:00
zzz
9b9f96daf8 i2psnark: Tweak 1st column sort order 2018-07-28 19:34:16 +00:00
zzz
b8437cd247 Console: Catch ISE in get/setAttribute() (ticket #1529) 2018-07-28 19:03:01 +00:00
zzz
63f0355680 Console: Prep for removing themes (ticket #2272) 2018-07-28 13:47:08 +00:00
zzz
2586db91c0 Router: Implement router.rejectStartupTime config (ticket #2285) 2018-07-27 15:58:14 +00:00
zzz
fc817b0ec0 NTCP2: Defer NTCP 1/2 classifiation until receiving 64 bytes 2018-07-26 12:17:50 +00:00
zzz
2f2ff4f181 Console: Split netdb output into pages 2018-07-26 12:15:42 +00:00
zzz
68e8e597e8 i2psnark: Disable gzip for KRPC
it's already disabled at the session level, but in case we change it later
2018-07-25 15:49:32 +00:00
zzz
e7202e0ee6 javadoc html fix 2018-07-25 15:46:20 +00:00
zzz
a700747595 warning tweak 2018-07-25 15:44:06 +00:00
zzz
0bcf9caf7a doc typo fix 2018-07-25 15:43:40 +00:00
zzz
41e20ae707 Utils: Don't truncate at a ZWJ 2018-07-25 15:34:23 +00:00
zzz
a6c506a176 Utils: Debug code to find double-frees 2018-07-25 12:51:40 +00:00
zzz
7338282bbe merge of '00fccb01d49a6b94638c648438bc4059e5ee0796'
and 'a6dc0bea5ee5569b71fa349be025d6a027d46a09'
2018-07-25 12:49:50 +00:00
meeh
f9fbc76dd0 Code changes:
* Port check to see if i2p is already running.
* All buttons in the menu should work now.
* Rewrote some C++ to Objective-C, which fits better with the integration.
* Misc cleanup.
* Made the launch of router repeatable.
2018-07-24 16:26:40 +00:00
meeh
2ee1a212c8 Added BufferedOutputStream to BaseExtractor for better performance. 2018-07-24 16:23:08 +00:00
meeh
fe41dec699 Adding OSX graphics. 2018-07-24 16:21:53 +00:00
slumlord
2893cbb2e6 Fix typos pointed out by yahoe.001 on transifex 2018-07-24 08:18:26 +00:00
zzz
18e24edce5 NTCP2: Fix double-free of buffers after msg3 p2 fails
Fix sending termination after msg3 p2 fails
2018-07-23 20:50:42 +00:00
zzz
f554ca3493 Console: Add support for IPv6 prefix lookup 2018-07-22 12:56:04 +00:00
str4d
03e10835fb Fix Gradle build 2018-07-21 15:19:46 +00:00
zzz
1470ea2d72 reduce more log levels 2018-07-21 13:27:28 +00:00
zzz
292b7e6dc1 NTCP2 (ticket #2286):
Fix error sending large message
Fix NPE after handshake failure
2018-07-21 13:11:41 +00:00
zzz
2800791f00 Test: Backport EdDSA junit changes from github; fixes NPE in 2 tests 2018-07-20 15:25:15 +00:00
zzz
c35d1583d4 NTCP2: Reduce log levels 2018-07-19 14:17:37 +00:00
zzz
412fcfb578 Console: Add netdb search by transport 2018-07-19 14:15:43 +00:00
zzz
80973ca21a Build: Add check for libtaglibs package in debian builds 2018-07-18 13:15:36 +00:00
zzz
1b0102bd1c i2psnark: Enable sequential order option for single-file torrents (ticket #2234) 2018-07-18 12:08:40 +00:00
zzz
2a68a01a35 Console: Fix HTML errors on /configservice w/o wrapper 2018-07-16 18:09:54 +00:00
zzz
63f4e04624 Router: Add CLI tool to generate family keys 2018-07-15 14:39:02 +00:00
zzz
6c3cf9bf77 I2CP: Add option for forcing gzip on/off per-message
Use option in streaming SYN and CLOSE packets
2018-07-15 13:50:31 +00:00
zzz
4ff62c291e NTCP: Increase failsafe sleep threshold for busy routers (ticket #2251)
Hardcode useDirectBuffers config
2018-07-15 11:39:30 +00:00
zzz
d4992936b1 i2psnark: Recreate deleted files on recheck/reopen (ticket #2125) 2018-07-14 17:09:51 +00:00
zzz
2a0b927022 i2psnark: CSS for in-order form (ticket #2234) 2018-07-13 16:58:55 +00:00
meeh
17c2a2a580 merge of '639a99d15ec0e7cbf0b44fd44564a6ae304b8673'
and '6b24962b7b3513e22153068b62922cabebb2dee4'
2018-07-13 10:10:14 +00:00
meeh
a92993e05b Added some more header files, and fixed much of the build system. 2018-07-13 10:10:04 +00:00
meeh
3fcef90cc2 merge of '3307710b35da5de0073b4b3e26fb33d180591563'
and '7532ae57e808a03a2c4500c861e320848729cb27'
2018-07-13 10:09:14 +00:00
meeh
8c78d4f83e A functional programming "library" (some headers with some magic love found in scala) 2018-07-13 10:09:08 +00:00
meeh
2daeb6d1a1 merge of '54817017a7af30d5a701bb76ce4c5f18479d525c'
and 'b90d952c362ac02ebfadf0049cfdca61e870cd87'
2018-07-13 09:12:25 +00:00
meeh
c8490a3140 Starting to get stable and usable. Basically everything is based on callbacks. 2018-07-13 09:11:46 +00:00
meeh
818e70d3a7 merge of 'aca699a4227d198b550c8579ebe091a1f5a2578e'
and 'e24559aa0df77c42ee3705237fe35ca3436a1bd5'
2018-07-13 06:30:22 +00:00
meeh
6d0f80fa1e Fixed a load of issues related to my "sync" approach, and Mac OSX's "async" API. 2018-07-13 06:30:16 +00:00
zzz
5fd1b69532 i2psnark: Sequential piece priority within each file (ticket #2234) 2018-07-12 15:34:13 +00:00
zzz
e24ebf4bda i2psnark: UI config for sequential download (ticket #2234)
Sort with Collator
CSS TODO
2018-07-12 13:41:44 +00:00
zzz
d34087f4d0 i2psnark: Stub out support for sequential download (ticket #2234) 2018-07-12 11:19:56 +00:00
zzz
b78870de54 NTCP2: Remove dup getHash() method 2018-07-11 14:25:43 +00:00
zzz
9d2f684ac7 Streaming: Change enforce protocol default to true 2018-07-11 13:04:13 +00:00
zzz
6ad1de8d85 Util: Convert more caches to TryCache (ticket #2263) 2018-07-10 21:21:32 +00:00
zzz
f6da5f43aa CPUID: Recognize Hygon processors 2018-07-10 20:33:23 +00:00
zzz
02669fafde SSU: Sync/notify improvements (ticket #2260) 2018-07-10 17:14:14 +00:00
zzz
30fc9544fe Installer: Fix Windows 10 64-bit install for IzPack 4/5 (ticket #1864)
Add more IzPack 5 build targets
2018-07-10 12:19:29 +00:00
zzz
307a68aa5a Installer: Add support for IzPack 5 (ticket #1864)
fix typo in postinstall.sh
2018-07-10 11:19:41 +00:00
meeh
2664c417e3 merge of '5a7bb5cbf6a37b5e282620eeb893459dc3ebe4af'
and 'b11d43f037fd0eb4248f7388e26af31209aaf0a2'
2018-07-08 13:16:16 +00:00
meeh
21b3864dfd Moved some logic to C++, which will extract i2p if it's not already,
and then secondly fire up the router in a second java process when 
extraction is completed. Gonna use "optional" type in C++ to make
global variables a bit less painful to use.
2018-07-08 13:16:07 +00:00
meeh
7a0f384dbf merge of '6b3a264a4dddd9667ce22ed517fbfccd5d676f9f'
and '95e2b9f35eac4e0ca2160d2f554bb4cdba5c074d'
2018-07-08 13:13:21 +00:00
meeh
27a0d4e51e Removing some Scala classes for the Mac OSX laucher,
since the C++ code replaces it's functionallity.
2018-07-08 13:12:51 +00:00
zab2
dfa1470c17 reinstate cache capacity calculation 2018-07-08 12:38:53 +00:00
zzz
d992dbf92a i2psnark: Add comment icon (ticket #2278) 2018-07-08 12:01:16 +00:00
zzz
1c28495fc3 propagate from branch 'i2p.i2p.zab.2263' (head 5d4d46ea16b13a188d27ff31c81a5362f20b6d68)
to branch 'i2p.i2p' (head 3ba7c5b2e24e950c83d6370df3c814fd025add81)
2018-07-08 11:36:53 +00:00
zzz
950ca71a34 NTCP2: Refactor padding size calculation
Avoid possible NPEs (ticket #2286)
Bundle up to 5 tunnel messages
Use read buffer to send RI and termination
Temp buf doesn't need 2 bytes for length
RI size check
Log tweaks
2018-07-08 11:00:54 +00:00
zzz
fcf82ea580 revert imports too 2018-07-08 11:00:02 +00:00
meeh
381f390938 Reverted change related to fatjar. We're using "real" base path in any case. 2018-07-07 12:27:07 +00:00
zab2
ab4a8ef16c reinstate capacity check 2018-07-06 17:13:48 +00:00
zab2
998931ffde propagate from branch 'i2p.i2p' (head 566b1eeda884669d179397966db673e71775debb)
to branch 'i2p.i2p.zab.2263' (head be0f0d7318f30334dcdbe7d2ef728d9611aff5f7)
2018-07-06 17:02:40 +00:00
zab2
67b7febf72 propagate from branch 'i2p.i2p' (head 6c6a7520cad38845cee83103c323782b426b3ff5)
to branch 'i2p.i2p.zab.2263' (head 727b9053d85f58811d1f5e05ccc697bfd9a454a2)
2018-07-06 16:59:14 +00:00
zzz
a916c1a22a NTCP: Read all available data when able (ticket #2243) 2018-07-06 13:31:46 +00:00
zzz
1460bec8cf SSU: Change remaining acks from List to Set (ticket #2258) 2018-07-06 13:27:38 +00:00
zzz
7aca1e4006 i2psnark: Fix comments wrapping (ticket #2284) 2018-07-05 15:07:05 +00:00
zzz
25e567a125 NTCP2: Increase max message size
OutNetMessage: Change size from long to int
2018-07-05 14:31:54 +00:00
zzz
43c2018177 i2psnark: Fix IOOBE when stopping torrent that is allocating (ticket #2273)
more sync in PartialPiece
2018-07-05 12:57:01 +00:00
zzz
7d9207dc81 NTCP: Don't advertise interface addresses when configured for force-firewalled
log tweaks
2018-07-04 16:22:56 +00:00
zab2
f9c3f82bb1 clear context reference when clearing cache 2018-07-04 16:13:36 +00:00
zab2
40b30979cd clear buf before releasing 2018-07-04 16:11:07 +00:00
zab2
11e00ba9cb move TryCache to core 2018-07-04 16:09:11 +00:00
zzz
9ac31573b4 Build: Move Jetty/Tomcat version properties to top-level build.xml 2018-07-01 14:16:56 +00:00
zzz
a895bcc91e NTCP2: Adjust padding defaults and size calculation
Rekey static after 30 days downtime
2018-07-01 13:42:59 +00:00
zzz
eff0cac30b EdDSA: Backport versions 0.2/0.3 from github:
- Change key encoding to match curdle draft
- Support key decoding based on curdle draft
- Implement true constant-time cmov()
- Add handling of X509Key-wrapped EdDSA keys (GitHub PR #47)
- Clarify that KeyPairGenerator takes a key size, not strength
- Javadocs
GitHub PR #58:
- Make GroupElement immutable by moving the pre-computed logic to the constructors,
  allowing the synchronized checking of whether the pre-computed logic had executed or not
  to be removed since it always has when it is used because those code paths
  are modified to request it at construction time.
- This allows getNegativeA() to be lazy, and doesn't need volatile due to the immutability
  (and final fields - this is important part of the contract with the JVM memory model).
- Remove synchronized contention from the named curve table get method.
- Generally remove use of the named curve table get method with a constant curve name
  in hot code paths in favour of using a new static constant for the curve spec.
Overall performance changes:
- Keygen 46% faster
- Signing 39% slower (due to cmov)
- Verify 2% faster
2018-07-01 11:10:06 +00:00
zzz
c65ce1d3f9 Router: Reselect jbigi lib when processor changes (ticket #2277) 2018-06-30 14:13:34 +00:00
zzz
201ef3b062 private field 2018-06-30 14:07:41 +00:00
zzz
3b34581065 Console: Fix reading flags when symlinked (ticket #2270) 2018-06-30 14:06:52 +00:00
meeh
d4dd0ea982 Adjustments in Scala code to adopt to work with the Obj-C++ code. 2018-06-30 13:11:17 +00:00
meeh
0b01cc5070 Adding codebase for the Objective-C++ part of the Mac OS X launcher/wrapper. 2018-06-30 13:10:06 +00:00
meeh
3de1fa2295 Minor change in routerconsole and core code for making I2P work great
in "portable" mode.
2018-06-30 13:07:41 +00:00
zzz
d8cc2a3560 Debian: Add build option for reproducible builds;
remove timestamp from manifests and javadocs (ticket #2279)
2018-06-28 18:47:45 +00:00
zab2
d42a467c00 forgot to set context 2018-06-28 17:40:14 +00:00
zab2
bc4ee0fc38 Implement tryLock-based object cache and make ntcp and ssu code use it 2018-06-28 17:33:34 +00:00
zzz
9b17b52b39 Debian: Add dependency for famfamfam-flag-png (ticket #2270) 2018-06-27 16:16:08 +00:00
zzz
c02f685307 Deb updates for 35 2018-06-27 14:52:55 +00:00
zzz
ef7b3e0c8b Core: misc. minor changes 2018-06-26 20:29:19 +00:00
zzz
baa11d8146 Console: Move modified flags to new directory,
in prep for symlinking original flags dir to package
for package installs (ticket #2270)
2018-06-26 19:11:53 +00:00
zzz
2d24f21327 Streaming: Enforce valid port in setters 2018-06-26 18:48:04 +00:00
zzz
96c565d486 Router: Misc. javadocs and debug 2018-06-26 18:45:11 +00:00
zzz
3c53dfe628 NTCP2: Remove static config on router rekey 2018-06-26 18:43:19 +00:00
zzz
761affc94d Console: Move servlet to new package (ticket #2265) 2018-06-26 18:39:39 +00:00
zzz
f0f62527d7 NTCP2: Show version on /peers 2018-06-26 16:57:29 +00:00
zzz
c826efd3a1 NTCP: Move runDelayedEvents() after the selector (ticket #2237) 2018-06-26 16:53:07 +00:00
zzz
ae8779e004 NTCP2: Establishment and data phase
- Address generation and validation fixes to match proposal changes
- Fixes for persistence of static s and iv
- Add methods for keygen and getters for static s and iv
- Add OutboundNTCP2State for outbound establishment
- Add support to InboundEstablishState
- Add data phase support to NTCPConnection
- Refactor NTCPConnection for multiple protocols
- Support concurrent pending outbound messages in NTCPConnection
NTCP1: Cleanups and performance improvements
- EventPumper tweaks and logging
- Eliminate extra data copy in NTCPConnection message sending
- Remove _meta field in NTCPConnection
- Locking changes in NTCPConnection and EstablishState classes
- Zero out DH keys when done
- Fix read when buffer position nonzero in NTCPConnection
- NTCPConnection make more methods package private
- Do AES decryption in data phase all at once when possible
- Drop expired outbound messages in NTCPConnection before sending
- Pass extra data from EstablishState directly to NTCPConnection
  to avoid race, remove getExtraBytes() method
- Remove getException, getError, getFailedBySkew methods and calls from Reader
2018-06-26 16:47:53 +00:00
zzz
49221add97 NTCP2: Noise library license, javadoc, .editorconfig 2018-06-26 16:11:46 +00:00
zzz
da810467b3 NTCP2: Noise library changes:
Use key factory for key pair generation
Hardcode Noise name and compute first hash in advance
Expose mixHash method so we can process message 1 and 2 padding
Add method to get chaining key and hash for siphash key generation
Remove unused patterns, methods, code
Debug and speed test code
Finals
2018-06-26 16:06:18 +00:00
zzz
70f018eb87 NTCP2: Noise lib from:
https://github.com/rweather/noise-java
Revision db4855c on Oct 8, 2016
Copyright (C) 2016 Southern Storm Software, Pty Ltd.
MIT license
Unmodified, as base for future merges
Only classes we need, this rev will not compile
2018-06-26 16:01:35 +00:00
zzz
55a8878a64 NTCP2: Key factory 2018-06-26 15:57:09 +00:00
zzz
0f048a7aa6 NTCP2: New FNDF method 2018-06-26 15:39:08 +00:00
zzz
435bf81945 NTCP2: Payload and options classes 2018-06-26 15:29:08 +00:00
zzz
1a56d5ab37 NTCP2: I2NP support, fixes, cleanups 2018-06-26 15:23:55 +00:00
zzz
3d21ad0df9 0.9.35 2018-06-26 11:09:29 +00:00
zzz
f6a4b0b709 Pull translation updates from Transifex
New Azerbaijani translations
2018-06-23 11:57:39 +00:00
zzz
199788495e Update HTML file list for test
Fix HTML error in Chinese eepsite help page
2018-06-23 11:08:42 +00:00
zzz
fecd0a9f5c GeoIPv6 from MaxMind 2018-06-04
No more updates for v4 legacy format, see ticket #2268
2018-06-23 10:44:22 +00:00
zzz
1e24523df2 volatile 2018-06-22 10:40:36 +00:00
zzz
93c6df7e89 SusiMail: Fix NPE on logout (ticket #2266) 2018-06-21 18:41:21 +00:00
zzz
e33bb2ac1e Console: Add Azerbaijani, add translated eepsite help pages
48x48 az.png converted from:
https://upload.wikimedia.org/wikipedia/commons/d/dd/Flag_of_Azerbaijan.svg
Public domain as specified on:
https://en.wikipedia.org/wiki/File:Flag_of_Azerbaijan.svg
2018-06-21 16:25:30 +00:00
zzz
07f7f2be50 i2psnark: Unstick the navbar (ticket #1996) 2018-06-21 12:31:22 +00:00
zzz
7ddeb0c945 i2psnark: Remove tracker links unless non-default 2018-06-21 11:13:29 +00:00
zzz
00c1fc6ed4 /logs version section tweaks (ticket #1996) 2018-06-21 10:38:31 +00:00
zzz
4a211f1bf4 Console: Don't display individual tx/rx graphs if displaying combined graph (ticket #2106) 2018-06-19 17:42:46 +00:00
zzz
776c7aeb83 Console: Restore line breaks in copy/pasted log entries (ticket #2078) 2018-06-19 14:28:37 +00:00
zzz
c143a0e807 i2psnark: Combine strings 2018-06-19 13:58:55 +00:00
zzz
6ea0b05300 /configui: Fix HTML, combine strings 2018-06-19 13:18:24 +00:00
zzz
39dfdad0d2 Add imagegen to standard webapps list 2018-06-19 12:57:21 +00:00
zzz
4cd9fe725d fix build 2018-06-19 11:32:19 +00:00
zzz
03d430ba7c SSU: Catch ISE 2018-06-19 10:31:02 +00:00
zzz
5592992b73 SSU: Add volatile (ticket #2260) 2018-06-19 10:26:57 +00:00
zzz
d500f61738 NTCP: Log and fail messages on outbound queue overflow 2018-06-17 16:00:17 +00:00
zzz
8eb6dc0aef GeoIP: Don't log error message when hitting the end
of the geoipv6.dat file
2018-06-16 17:23:57 +00:00
zzz
dd5c4af6fb Console: Less hats and cats 2018-06-15 22:38:13 +00:00
zzz
0756306e54 SusiMail: CSS fixes (ticket #2242) 2018-06-15 22:05:43 +00:00
zzz
5e24daafc6 disable NTCP2 code 2018-06-15 19:16:06 +00:00
zzz
37bb09ffc7 new irc server 2018-06-15 13:46:50 +00:00
zzz
89c9a6d0bb Push strings to transifex 2018-06-13 18:33:56 +00:00
zzz
04bf5157bb build time debug tweak 2018-06-13 14:15:05 +00:00
zzz
790db3735f update build time 2018-06-13 14:12:34 +00:00
zzz
78b2d24001 Jetty: Add TX config for eepsite help page (ticket #2214)
and for testing readme.html for .36
2018-06-13 12:15:59 +00:00
zzz
14e4cba7cd SSL Wizard tweaks 2018-06-13 11:57:50 +00:00
zzz
b1541dbf11 Eepsite help: more edits 2018-06-13 11:43:23 +00:00
zzz
da5de2fd4a NTCP: Fix clearing of write interest ops at
inbound establishment, causing latency on first message
(ticket #2237)
2018-06-13 10:42:53 +00:00
zzz
aa98e540e0 Catch RuntimeException in BuildRequestor 2018-06-11 12:11:03 +00:00
zzz
253c157ba8 Don't exclusively use explicitPeers when specified for testing 2018-06-11 12:10:04 +00:00
zzz
9c35a55969 enforce max family name length 2018-06-11 12:06:34 +00:00
zzz
a1bf2b8653 console changelog disable horizontal scroll 2018-06-11 12:02:29 +00:00
zzz
3361d14f3c UPnP: Change port names 2018-06-11 11:56:22 +00:00
slumlord
e687e1d4d5 #2242 - CSS changes for dark theme so that Folder button and drop-down menu have visible text. Could cause problems elsewhere, still testing 2018-06-11 09:23:51 +00:00
zzz
56bf844540 eepsite: More help page updates (ticket #2214)
Rename help page background image file, it's not Bulgaria
Delete all help page country flag files, we already copy them in build.xml
2018-06-10 13:16:55 +00:00
slumlord
ee5012311e #2214 - Update instructions for adding a key/hostname on stats.i2p; Remove external links, add search suggestion and specific warning about apache modules 2018-06-09 18:18:47 +00:00
zzz
3f92d92ce4 eepsite: More help page fixes (ticket #2214)
Re-enable dir listings, required for help page links
2018-06-09 16:48:57 +00:00
zzz
20145333f4 i2psnark: Fix torrent ignoring priority settings when autostart is enabled (ticket #2229) 2018-06-09 13:42:12 +00:00
zzz
7b3791627c Eepsite Help: Updates for translation (ticket #2224)
Remove dead links and commented-out text
Put each sentence on separate line
Clarify and simplify language
2018-06-09 11:54:03 +00:00
slumlord
98019bb998 Updates to eepsite help page 2018-06-08 11:32:35 +00:00
zzz
5c3f264295 NTCP: More efficient copying of inbound establish state data
More prep for NTCP2
2018-06-03 13:12:21 +00:00
zzz
02855a0d97 NTCP: Fix state lock, should not have been static
javadocs
2018-06-02 17:03:26 +00:00
zzz
b5117eafc5 NTCP2: Data phase payload generation and parsing 2018-06-02 15:53:06 +00:00
zzz
05ffa63dc0 NTCP: Start NTCP2 implementation, all disabled for now 2018-06-02 15:05:24 +00:00
zzz
06106c75dc NTCP: Refactor EstablishState into interface/base/inbound/outbound,
in prep for NTCP2
2018-06-02 12:35:11 +00:00
zzz
363aaadb1a Console: Sort tunnels within pools by expiration (ticket #2232) 2018-06-02 12:28:50 +00:00
zzz
7713284e64 SusiDNS: Fix deleting notes (ticket #1433)
Hide advanced fields in published entries
2018-06-01 12:25:08 +00:00
zzz
cee45e3031 SusiDNS: Add notes form (ticket #1433) 2018-05-31 20:33:31 +00:00
zzz
24a1cf713e Console: Change Java 10 warning to Java 11,
since bionic uses 10
2018-05-31 17:16:00 +00:00
zzz
481e28750b Console: Fix CSS preventing ordered lists (ticket #2075) 2018-05-31 15:34:37 +00:00
zzz
8b029dbae5 SusiMail: Message button tweaks 2018-05-31 00:37:45 +00:00
zzz
484d4e226c SusiMail: Don't require confirmation to delete from Trash,
Clear reallydelete flag when clicking cancel or change folder
2018-05-30 23:51:14 +00:00
zzz
a7db82a1fa SusiMail: Fix dup ConnectWaiter run, no failure message 2018-05-30 19:46:51 +00:00
zzz
3f2fe39515 SusiMail: Don't store loading/fetching/refresh messages in session object,
so they go away when done
2018-05-30 15:55:19 +00:00
zzz
04a9f5612b Javadoc fixes 2018-05-30 13:11:50 +00:00
zzz
884a42b814 Build: Remove more files from Debian source tarballs
Don't need to both delete and exclude for tarballs
Restore commons-logging.jar to build classpath where needed for deb builds
Add classpath entries to fix Debian javadoc build
2018-05-30 12:52:30 +00:00
zzz
278a8142b8 NTCP: Cleanup, remove commented-out code in prep for NTCP2
Increase max RI size
2018-05-29 17:23:08 +00:00
zzz
277a1619e4 Console: Tagged string fixes (ticket #2017)
CSS tweaks
2018-05-28 17:49:47 +00:00
zzz
d128bab2fa SusiMail: Send deletions after connect so emails don't come back after a move (ticket #2087)
Refactor/consolidate pop3 deletion code
Fix loading mails in checker
Fix checker thread name
Return to inbox, not drafts, after sending draft
CSS for select
2018-05-28 14:18:23 +00:00
zzz
550ef2ae9c SusiMail: Remove disk null checks, always non-null 2018-05-27 13:46:13 +00:00
zzz
5feeffa550 ministreaming: Add classpath to jar (ticket #2228) 2018-05-26 22:03:16 +00:00
zzz
36c279f23d i2psnark: Hide peers button if no peers on that page (ticket #2152) 2018-05-26 21:47:30 +00:00
zzz
f3207464bb i2psnark: Hide column 1 icon for peers (ticket #1996) 2018-05-26 21:07:42 +00:00
zzz
00acac4b61 i2psnark: Hide "0 Bps" if no peers (ticket #2152) 2018-05-26 20:59:09 +00:00
zzz
e67c750fab i2ptunnel: Retry accept after server socket closed (ticket #2003) 2018-05-26 20:00:10 +00:00
zzz
2d7f0d35ce i2ptunnel CLI help tweak 2018-05-26 19:52:41 +00:00
zzz
3701f71fc6 Jetty: Skip files with [] in default servlet to avoid throwing exception 2018-05-26 19:31:40 +00:00
zzz
3f64825436 SSL Wizard: Cleanups 2018-05-26 17:38:33 +00:00
zzz
5ca319e4bd /confignet: Reorganize (ticket #2217) 2018-05-26 16:05:28 +00:00
zzz
f11104e7bc Summary Bar: Change header from "I2P Updates" to "Update Status" (ticket #2137)
/configsidebar: Tag sections for translation; translate unselected sections;
sort unselected sections by translated name
2018-05-26 13:56:06 +00:00
zzz
39c0f558c1 Utils: Disable DNSoverHTTPS by default (ticket #2201)
Reenable with eepget.useDNSOverHTTPS=true and time.useDNSOverHTTPS=true
2018-05-26 12:24:50 +00:00
zzz
c1b9aa9665 Router: Fix wrapper.config path in OOM message when installed as
Debian package, but not running as a service (ticket #2223)
2018-05-26 11:46:59 +00:00
zzz
9eb3cc5916 i2ptunnel: Fix dup tunnels clicking generate on new tunnel (ticket #2225)
remove dup call to processAction()
2018-05-25 19:39:22 +00:00
zzz
2fab97fb20 Console: Fix changes to wrong tunnel on /configtunnels (ticket #2227) 2018-05-25 17:35:29 +00:00
zzz
195a2d0473 LICENSE.txt clarifications and updates 2018-05-06 15:50:28 +00:00
zzz
288a6b0670 SSL Wiz: Use RSA if EC not available 2018-05-06 13:25:40 +00:00
zzz
df7c1c6104 Certs: Change default from RSA to EC for CA certs 2018-05-06 13:21:22 +00:00
meeh
598a177e5e Removed a "ant-" which wheren't supposed to be commited :) 2018-05-06 03:58:08 +00:00
meeh
0a1191aa3f Small patch to make ant use the SBT wrapper script. 2018-05-06 00:20:54 +00:00
meeh
5f81a8de59 Mac OS X Launcher - reborn - ALPHA!
TLDR;
Howto? ant osxLauncher
Privacy Notes? If you don't got SBT, a bash script will trigger
               download of SBT for you with task osxLauncher.
Results? open ./launchers/output
"Binary" App Bundle name: I2P.app
Runtime base directory? ~/Library/I2P
Runtime config directory? untouched.

After talk on IRC with zzz, I rewrote the logic since we could
start with a simple deploy, for a faster alpha version ready :)

SBT will build a zip file from the content of pkg-temp, which
CompleteDeployment.scala will again unzip in runtime. Right now
it's quite basic, but the plan is to add version detection, so
it's capable of upgrading a already deployed I2P base directory.

OSXDeployment.scala is renamed to PartialDeployment.scala for usage
in the browser bundle launcher, since it's going to be a subset of
the files found in pkg-temp.

A Info.plist is added to the launchers/macosx which is added to the
application bundle under building. Note that this differ from the one
in Start i2p router.app that's been here for years now.
2018-05-05 23:34:35 +00:00
zzz
f6273a1662 SSL Wizard: Link fixes
Fix lost autostart config
Separate messages for bad SSL config vs. no SSL config
2018-05-05 22:32:43 +00:00
zzz
e14a4f0111 HTTP Client: Allow SSL to i2p hosts by default 2018-05-05 22:25:13 +00:00
zzz
543e5bd218 Preliminary .editorconfig 2018-05-05 22:22:40 +00:00
zzz
d3c28a6b44 Streaming: Don't send HTTP response to HTTPS request 2018-05-05 22:21:01 +00:00
zzz
d851686272 SSL Wizard: Add links 2018-05-05 14:09:47 +00:00
zzz
87329bc32c SSL Wizard: Page cleanup, message box 2018-05-05 12:59:01 +00:00
zzz
c734b84b28 doc update 2018-05-03 20:40:26 +00:00
zzz
6c88eb5211 BOB: Register with port mapper 2018-05-03 20:00:03 +00:00
zzz
7b2355a888 SSL Wizard: Implement Jetty SSL disable 2018-05-03 19:43:22 +00:00
zzz
b31ebfe368 SSL Wizard: Stop and restart Jetty if running
Make JettyStart restartable
RouterAppManager workaround for JettyStart becoming untracked after stop
2018-05-03 19:29:13 +00:00
zzz
9a7b58259f CLI: Add KeyGenerator 2018-05-03 13:13:29 +00:00
zzz
9c52d454f8 Debug: Case-insensitive sort of PortMapper and AppManager tables 2018-05-03 13:08:56 +00:00
zzz
a548c307bc Console: Make Java 10 warning a 10/11 warning 2018-05-03 13:01:16 +00:00
zzz
2efd544713 Tests: Add scala files to UTF-8 tests
Make tests less noisy
2018-05-03 13:00:08 +00:00
zzz
c9a6fab638 SSL Wizard: Implement disable-SSL 2018-05-02 13:39:49 +00:00
zzz
1c677cd99b SSL Wizard: Fixes, checks, form improvements 2018-05-02 13:10:06 +00:00
meeh
70e994fcf3 Some changes, after much testing I find it best to spawn an sub java
process for I2P rather than trying to load Router via reflection or
anything runtime fancy stuff. Shell script is implemented in SBT now,
and can now link to download JRE script and so on.
2018-05-02 03:39:14 +00:00
meeh
c326bb7c6d Added scala license snippet to LICENSE.txt 2018-05-01 13:30:55 +00:00
meeh
f6c8e44329 Jar deployment, SBT hacking, and more related to launcher code.
Some refactoring, bugfixing, and self awareness of launcher jar.
2018-05-01 11:15:11 +00:00
meeh
345e7414e6 Change current directory to base directory before starting the router. 2018-05-01 03:43:41 +00:00
meeh
3488db38bc Moved a function to a more logic place. 2018-05-01 03:40:07 +00:00
meeh
8957c85486 Disable debug messages. 2018-05-01 03:36:59 +00:00
meeh
6b0a102c1b Updating code to handle multiple(no limit) recursive levels. 2018-05-01 03:35:09 +00:00
meeh
975d8a069a Cleaned up in SBT build file. Sorted assignments, task definitions and such. 2018-05-01 03:21:04 +00:00
meeh
2d15f8e16e Improved code documentation and readableness in form of syntax cleanup. 2018-05-01 03:15:44 +00:00
meeh
a3a8ee1329 Major update for the OSX Launcher code. Now it will bundle
installer resources with the fat jar (we add an exclusion list later)
which the base directory will be built(or updated if lacking files) upon
startup of the I2P router. This is done by the OSXDeployment class which
is an extension for the DeployProfile class written for Mac OS X.

Since the app bundle itself should be R/O, we use ~/Library/I2P as base path,
and continue using ~/Library/Application Support/i2p as config path. The BB
code will have other paths.
2018-05-01 02:54:36 +00:00
zzz
4e5a2d00aa SSL Wizard: Move old keystore before rewriting
Fix password setting in XML
Add DTD to rewritten XML
2018-04-30 16:45:01 +00:00
zzz
ab039b8023 SSL Wizard: Update and save tunnel config 2018-04-30 13:59:23 +00:00
zzz
8ed1b96f3a Console: Fix NPE on /configsidebar (ticket #2220)
Don't throw NPE translating null
Add note about split()
Fix form inside table
2018-04-29 20:57:47 +00:00
meeh
c73b5b9edb merge of '4d8cced5819f256dd03cd1a845bcb08fe8de9319'
and '76cdc242b9b68e5fef39dfe67cf27baf29872f2f'
2018-04-29 18:51:38 +00:00
meeh
e308804cb7 Removing some resources. 2018-04-29 18:51:31 +00:00
zzz
cdd58f168a SSL Wizard: Change cert type, export cert, show in cert helper,
relay keystore password via POST
2018-04-29 15:46:30 +00:00
zzz
4d09e507fb SSL Wizard: Move some things to make the classloader happy
Rewrite clients.config
2018-04-29 14:32:01 +00:00
zzz
d600a2df12 Build: Remove references to now-empty commons-logging.jar 2018-04-28 22:17:19 +00:00
zzz
e310588273 SSL wizard: Start of POST handling
Work around Jetty XML bug
classpath fixes to follow
2018-04-28 22:07:14 +00:00
zzz
a0fabe5f92 i2ptunnel: Fix startup deadlock in TCG 2018-04-28 21:58:13 +00:00
zzz
780fdfe4f6 Console: Add POST support to the error handler so it doesn't error itself 2018-04-28 18:37:59 +00:00
zzz
145730f5b8 SSL wizard: Add missing file, fix form params 2018-04-28 15:25:05 +00:00
zzz
624a672213 i2ptunnel: Initial SSL setup wizard
Includes Jetty XML configuration parser
Work in progress, doesn't work, not linked from anywhere
2018-04-28 13:21:42 +00:00
zzz
16c5252c43 Jetty: Dir listing time format tweak 2018-04-28 11:32:36 +00:00
zzz
50710f8066 Tunnels: Fix and consolidate allow-zero-hop logic,
prevent zero-hop client tunnels even when no active peers
Remove buildRequestZeroHopTime stat
2018-04-27 17:41:47 +00:00
zzz
10c6c428a3 SusiMail: Don't zip encrypted.asc PGP attachment 2018-04-26 13:43:20 +00:00
zzz
c34fd76a78 Proxy: Don't generate footer hidden by CSS 2018-04-25 14:27:40 +00:00
zzz
ab9dac8827 Migrate webapp detection calls to PortMapper.isRegistered() 2018-04-25 14:21:23 +00:00
meeh
49ba58cb8d Updated history.txt again. 2018-04-24 05:04:11 +00:00
meeh
4f47fab139 Removed unused resources directory hopefully,
And aslo added an IconHelper autoplugin which
will generate Mac OS X valid ICNS images.
2018-04-24 05:01:25 +00:00
meeh
832e55ddf9 Updated history.txt for today. 2018-04-24 04:28:37 +00:00
meeh
8adf55a568 Still WIP, but I've added a new sbt plugin named
sbt-native-packager for future rpm/deb/windows and 
maybe even OSX packages. Also, the macosx sbt project 
now has a task named buildAppBundleTask and which will 
produce an I2P.app and copy over needed directories/jars/wars
which later needs to be extracted to an writeable area which
would be i2p base directory in runtime.

The MacOSXRouterLauncherApp contains more information about how 
the executable in the OS X bundle will locate our R/O i2pbase so 
it can copy it to a writable area. The R/O is also to ensure valid
signature on the bundle.

At last, this approach is done casue letting an Mach-O binary load
libjvm.dylib was proved unstable, so MacOSXRouterLauncherApp will 
rather use an JNI module to load the needed glue with the 
Mac OS X system.
2018-04-24 04:18:21 +00:00
meeh
9307b27655 Update in the install_i2p_service_osx.command script. 2018-04-24 04:09:20 +00:00
meeh
345d078370 Updating ignore file to ignore sbt build directories. 2018-04-24 04:08:25 +00:00
meeh
a4ef4e594a Update history.txt of yesterdays work. 2018-04-24 00:49:22 +00:00
meeh
18b11d2a32 Reducing the amount of "items" in the root of the repo
by moving documents into a own docs directory.
2018-04-24 00:48:08 +00:00
zzz
75d681a93c Clock: Fix early NPE via DoH 2018-04-23 15:48:44 +00:00
zzz
0500bbb186 EepGet: Handle HTTP response line with no status text 2018-04-23 15:46:35 +00:00
meeh
a047b91deb Added a section "SBT Behind proxy" 2018-04-23 00:26:53 +00:00
meeh
e941e79830 Doing it the right way and add license for Scala (BSD-3) 2018-04-23 00:19:32 +00:00
meeh
b98254b2be Updating README.md making contribution/hacking guide/docs more available,
this is specially important for our GitHub impression which I suspect most 
coders will have their first meeting with I2P on. The documentation is far from
done but it should make value for any new developer by this time so I've decided 
to push them. It losly describes our build systems, and has a monotone cheat sheet 
which always has an "git equalent" so it's easier to handle for people used to git.
2018-04-23 00:14:23 +00:00
meeh
e8ac24bedd Added some missing files from earlier commits caused by -R stuff in mtn. 2018-04-22 23:48:44 +00:00
meeh
38e109db2b Added new ant targets to the overview of targets. 2018-04-22 23:16:04 +00:00
meeh
8c10ec9db3 Realised a better way to handle the build process of both the
Browser Bundle i2p launcher, as well as the upcoming Mac OS X
i2p launcher. They share some few properties and how code has
to be managed for both system's update managers and so on.
More details will be documentated in README.md files as well as
in those commit messages I now write :)
2018-04-22 23:13:32 +00:00
meeh
b9a2459315 Adding missing files since shitty monotone needs an -R in add. :) 2018-04-22 20:37:39 +00:00
meeh
86f8d63a69 WIP: Adding most of the launcher code now to the repo, the one for the browser bundle.
Not 100% completely done but ready for commenting/review.
2018-04-22 19:56:42 +00:00
zzz
1a27fe185c SusiMail: Include attachments when forwarding (ticket #2087) 2018-04-22 15:17:38 +00:00
zzz
0573123460 SusiMail: Remove draft fields from session object 2018-04-22 13:59:10 +00:00
zzz
1e33dac2d7 SusiMail: Reply/fwd immediately saves as draft rather than
passing data through session; re-enable P-R-G
New StringBuilderWriter util
2018-04-22 12:34:49 +00:00
zzz
98663feaa3 SusiMail: Refactor draft compose/save in prep for fixes 2018-04-21 11:58:26 +00:00
zzz
ceeacf6a07 SusiMail: Remove Bcc-to-self feature,
replace with copy-to-sent config (ticket #2087)
2018-04-21 11:18:58 +00:00
zzz
f040421848 SusiMail: Fix reply/forward filling in compose form
Better formatting of addresses in forwarded mail
2018-04-19 21:20:58 +00:00
zzz
9fcddbb6bf SusiMail: Initial CSS for new buttons 2018-04-18 16:42:44 +00:00
zzz
75c20c9b1a SusiMail: Fix unhandled decoding exception
Trim leading whitespace from charset
2018-04-18 15:45:43 +00:00
zzz
ea9a3320a3 DNSoverHTTPS for SSLEepGet and NTP (ticket #2201) 2018-04-17 17:16:51 +00:00
zzz
d621e19349 json-smart-v1 lib for DoH and i2pcontrol
Copied from i2p.plugins.i2pcontrol.
Does not include JSON-RPC2, that stays in the plugin.
i2pcontrol checkin notes:
Smart Mini files (net.minidev.json) from:
https://github.com/netplex/json-smart-v1
commit 51e1641 on Oct 23, 2015
Essentially version 1.3.2 (1.3.1+)
Licensed Apache 2.0.
Removed as unneeded: JSONNavi.java, JSONStyleIdent.java
Not in Debian/Ubuntu
Version in Maven Central (1.0.8) is too old
2018-04-17 17:01:24 +00:00
zzz
1ba7fb9621 BuildTime: Update, add to cmd line tools 2018-04-17 13:28:47 +00:00
zzz
d02b71a39e SusiMail: Fix error message on login page 2018-04-17 13:21:44 +00:00
zzz
f0e0c01518 Console: Fix sidebar status when updating plugin (ticket #2137) 2018-04-17 12:37:54 +00:00
zzz
76999ccb6f Console: Cleanups when no leases/tunnels 2018-04-16 14:44:42 +00:00
zzz
d189c3912c Console: Add links to bandwidth graphs on /tunnels 2018-04-16 14:34:41 +00:00
zzz
b9bc254fd3 SusiMail: Move logging to router logs (ticket #2191) 2018-04-16 11:06:18 +00:00
zzz
8c0e82d4f3 i2ptunnel build restructuring:
Move Messages class from web to ui package, and from jar to war.
Build web package in a separate pass (prep for ssl helper)
API notes in javadocs
Hopefully doesn't break Android build
2018-04-14 18:54:17 +00:00
zzz
844977cca3 SusiMail: Add folders, drafts, background sending (ticket #2087)
Use with caution; cleanups and CSS to follow
2018-04-14 15:50:07 +00:00
zzz
ffad52e48c LoadClientAppsJob.parseArgs() minor cleanup 2018-04-14 14:35:53 +00:00
zzz
d12b531c54 Jetty: Fix quote in header line tripping XSS filter (ticket #2215) 2018-04-14 13:25:25 +00:00
zzz
941db3aeeb Console: Add built-by to /logs (ticket #2204) 2018-04-14 13:12:40 +00:00
zzz
98aafee53a CPUID: Fix TBM detection (ticket #2211) 2018-04-14 12:55:50 +00:00
zzz
abec6ad64c Debian Buster updates (ticket #2027)
As pulled out of http://http.debian.net/debian/pool/main/i/i2p/i2p_0.9.34-1.debian.tar.xz
License file update
2018-04-14 12:38:39 +00:00
zzz
2f53f25580 Debian updates (ticket #2027, PR #15) 2018-04-14 12:15:28 +00:00
zzz
b374b1136e Jetty 9.2.24-v201801015, Tomcat 8.5.30 2018-04-11 18:24:37 +00:00
zzz
57e21e906f Debian updates for 0.9.34 2018-04-11 16:10:08 +00:00
meeh
a474bd46d6 merge of '3acb036bb44bfe12916742877b1b2298ef6a156a'
and '674ef573b3a8e4620f0e06397e062d86fc87a5a9'
2018-04-10 15:23:41 +00:00
meeh
7ae8381465 Fixed mistake + added @since 2018-04-10 15:22:21 +00:00
zzz
f00ac6ad14 merge of '13e60de3d602be3958686f91b450707dda0767b9'
and '7d04d994f5d52eb6e483ee8654f9314ec9997387'
2018-04-10 14:30:00 +00:00
meeh
5bef86f456 Adding initial support to the router for a more slim/portable runtime environment. 2018-04-10 13:52:46 +00:00
meeh
4d23e1d38f Corrected a wrong path, and extended info about i2ptunnel. 2018-04-10 13:51:14 +00:00
str4d
4ac505959f merge of 'b1fd7a753b83b73c005bf281fcd7e1e7046d81f6'
and 'c3b63d8b51f340bd41f9f1b8d64b78bec7a7c0c0'
2018-04-07 00:54:18 +00:00
meeh
683e0f42bc Too quick to push, fixed descriptions :) 2018-04-06 23:48:08 +00:00
meeh
d67cee5e45 Added a partially done directory structure cheatsheet thingy. 2018-04-06 23:39:23 +00:00
1669 changed files with 213535 additions and 315205 deletions

67
.editorconfig Normal file
View File

@@ -0,0 +1,67 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4
[{*.bat,**/*.bat,installer/resources/proxy/*.ht}]
end_of_line = crlf
[**/*.css]
indent_size = 5
[{history.txt,LICENSE.txt}]
indent_size = 3
[**/.project]
indent_style = tab
[README.txt]
indent_style = tab
[apps/BOB/**/*.java]
indent_style = tab
[apps/routerconsole/java/src/com/vuze/plugins/mlab/tools/ndt/swingemu/*.java]
indent_style = tab
[apps/routerconsole/java/src/edu/internet2/ndt/*.java]
indent_style = tab
[apps/routerconsole/jsp/{createreseed.jsp,exportfamily.jsp,flags.jsp,index.jsp,viewhistory.jsp,viewrouterlog.jsp,viewstat.jsp,viewtheme.jsp,viewwrapperlog.jsp}]
insert_final_newline = false
[apps/susimail/**/{*.java,*.js}]
indent_style = tab
[apps/susimail/**/{Attachments.java,MailPart.java,WebMail.java}]
end_of_line = crlf
[core/java/src/com/nettgryppa/**/*.java]
indent_size = 2
[core/java/src/gnu/**/*.java]
indent_size = 2
[core/java/src/gnu/getopt/*.properties]
charset = iso-8859-1
[core/java/src/org/json/simple/**/*.java]
end_of_line = crlf
indent_style = tab
[core/java/src/com/southernstorm/**/*.java]
indent_style = tab
[router/java/src/org/cybergarage/**/*.java]
indent_style = tab
[router/java/src/org/freenetproject/*.java]
indent_style = tab
[router/java/src/com/southernstorm/**/*.java]
indent_style = tab

53
.idea/compiler.xml generated
View File

@@ -1,22 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="addressbook_main" target="1.7" />
<module name="addressbook_test" target="1.7" />
<module name="BOB_main" target="1.7" />
<module name="BOB_test" target="1.7" />
<module name="core_main" target="1.7" />
<module name="core_test" target="1.7" />
<module name="desktopgui_main" target="1.7" />
<module name="desktopgui_test" target="1.7" />
<module name="i2psnark_main" target="1.7" />
<module name="i2psnark_test" target="1.7" />
<module name="i2ptunnel_main" target="1.7" />
<module name="i2ptunnel_test" target="1.7" />
<module name="installer_main" target="1.7" />
<module name="installer_test" target="1.7" />
<module name="jetty_main" target="1.7" />
<module name="jetty_test" target="1.7" />
<module name="jrobin_main" target="1.7" />
<module name="jrobin_test" target="1.7" />
<module name="ministreaming_main" target="1.7" />
<module name="ministreaming_test" target="1.7" />
<module name="router_main" target="1.7" />
<module name="router_test" target="1.7" />
<module name="routerconsole_main" target="1.7" />
<module name="routerconsole_test" target="1.7" />
<module name="sam_main" target="1.7" />
<module name="sam_test" target="1.7" />
<module name="streaming_main" target="1.7" />
<module name="streaming_test" target="1.7" />
<module name="susidns_main" target="1.7" />
<module name="susidns_test" target="1.7" />
<module name="susimail_main" target="1.7" />
<module name="susimail_test" target="1.7" />
<module name="systray_main" target="1.7" />
<module name="systray_test" target="1.7" />
</bytecodeTargetLevel>
</component>
</project>

53
.idea/modules.xml generated
View File

@@ -2,25 +2,78 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" group="apps/BOB" />
<module fileurl="file://$PROJECT_DIR$/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/apps/BOB/BOB.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" group="apps/BOB" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" group="apps/BOB" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" group="apps/addressbook" />
<module fileurl="file://$PROJECT_DIR$/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/apps/addressbook/addressbook.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" group="apps/addressbook" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" group="apps/addressbook" />
<module fileurl="file://$PROJECT_DIR$/apps/admin/admin.iml" filepath="$PROJECT_DIR$/apps/admin/admin.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/apps.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/apps.iml" group="apps" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/core/core.iml" filepath="$PROJECT_DIR$/core/core.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_main.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_main.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_test.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_test.iml" group="core" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" group="apps/desktopgui" />
<module fileurl="file://$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" group="apps/desktopgui" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" group="apps/desktopgui" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" filepath="$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" group="apps/i2psnark" />
<module fileurl="file://$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" group="apps/i2psnark" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" group="apps/i2psnark" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" group="apps/i2ptunnel" />
<module fileurl="file://$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" group="apps/i2ptunnel" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" group="apps/i2ptunnel" />
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" filepath="$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" />
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" filepath="$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer.iml" group="installer" />
<module fileurl="file://$PROJECT_DIR$/installer/installer.iml" filepath="$PROJECT_DIR$/installer/installer.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" group="installer" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" group="installer" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" group="apps/jetty" />
<module fileurl="file://$PROJECT_DIR$/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/apps/jetty/jetty.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" group="apps/jetty" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" group="apps/jetty" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" group="apps/jrobin" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" group="apps/jrobin" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" group="apps/jrobin" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" group="apps/ministreaming" />
<module fileurl="file://$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" group="apps/ministreaming" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" group="apps/ministreaming" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router.iml" group="router" />
<module fileurl="file://$PROJECT_DIR$/router/router.iml" filepath="$PROJECT_DIR$/router/router.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_main.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_main.iml" group="router" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_test.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_test.iml" group="router" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" group="apps/routerconsole" />
<module fileurl="file://$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" group="apps/routerconsole" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" group="apps/routerconsole" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" group="apps/sam" />
<module fileurl="file://$PROJECT_DIR$/apps/sam/sam.iml" filepath="$PROJECT_DIR$/apps/sam/sam.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" group="apps/sam" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" group="apps/sam" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" group="apps/streaming" />
<module fileurl="file://$PROJECT_DIR$/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/apps/streaming/streaming.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" group="apps/streaming" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" group="apps/streaming" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" group="apps/susidns" />
<module fileurl="file://$PROJECT_DIR$/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/apps/susidns/susidns.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" group="apps/susidns" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" group="apps/susidns" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" group="apps/susimail" />
<module fileurl="file://$PROJECT_DIR$/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/apps/susimail/susimail.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" group="apps/susimail" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" group="apps/susimail" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" group="apps/systray" />
<module fileurl="file://$PROJECT_DIR$/apps/systray/systray.iml" filepath="$PROJECT_DIR$/apps/systray/systray.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" group="apps/systray" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" group="apps/systray" />
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" filepath="$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" />
</modules>
</component>

View File

@@ -50,6 +50,17 @@ core/c/jcpuid/msvc/*.user
# Build property overrides
override.properties
# Launcher build paths
launchers/macosx/target
launchers/browserbundle/target
launchers/macosx/project/target
launchers/browserbundle/project/target
launchers/target
launchers/project/target
launchers/common/target
launchers/output
launchers/project/project
# Reporting
sloccount.sc
^reports/
@@ -62,3 +73,18 @@ sloccount.sc
# IDEA
\.iml$
# Meeh stuff
target/scala-2.12
target/streams
project/target
launchers/macosx/version.h
launchers/macosx/project/project/target
launchers/macosx/I2PLauncher.xcodeproj/project.xcworkspace/xcuserdata
launchers/macosx/I2PLauncher.xcodeproj/xcuserdata
launchers/macosx/I2PLauncher.xcworkspace/xcuserdata
launchers/macosx/Sparkle.framework
launchers/macosx/I2PLauncher.app
launchers/macosx/releases.done
launchers/macosx/target

View File

@@ -1,8 +1,12 @@
language: java
jdk:
- oraclejdk11
- oraclejdk9
- openjdk8
- openjdk12
- openjdk11
- openjdk10
- openjdk9
matrix:
include:
@@ -10,18 +14,25 @@ matrix:
addons:
sonarcloud:
organization: "i2p"
before_install:
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
- sed -i "1iplugins {\n id 'org.sonarqube' version '2.6.1'\n}\n" build.gradle
- jdk: openjdk8
before_install:
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
- jdk: openjdk7
sudo: required
before_install: # Work around missing crypto in openjdk7
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
- sudo wget "https://bouncycastle.org/download/bcprov-ext-jdk15on-158.jar" -O "${JAVA_HOME}/jre/lib/ext/bcprov-ext-jdk15on-158.jar"
- sudo perl -pi.bak -e 's/^(security\.provider\.)([0-9]+)/$1.($2+1)/ge' /etc/java-7-openjdk/security/java.security
- echo "security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" | sudo tee -a /etc/java-7-openjdk/security/java.security
before_install:
- |
if [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
sed -i "1iplugins {\n id 'org.sonarqube' version '2.6.1'\n}\n" build.gradle
fi
install:
- export TARGET_JAVA_HOME=$JAVA_HOME
- jdk_switcher use oraclejdk8
- ./gradlew assemble
allow_failures:
- jdk: openjdk12
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock

View File

@@ -36,6 +36,7 @@ source_lang = en
trans.ar = apps/i2ptunnel/locale-proxy/messages_ar.po
trans.cs = apps/i2ptunnel/locale-proxy/messages_cs.po
trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
trans.el = apps/i2ptunnel/locale-proxy/messages_el.po
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
trans.fi = apps/i2ptunnel/locale-proxy/messages_fi.po
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
@@ -46,6 +47,7 @@ trans.it = apps/i2ptunnel/locale-proxy/messages_it.po
trans.ko = apps/i2ptunnel/locale-proxy/messages_ko.po
trans.nb = apps/i2ptunnel/locale-proxy/messages_nb.po
trans.nl = apps/i2ptunnel/locale-proxy/messages_nl.po
trans.nn = apps/i2ptunnel/locale-proxy/messages_nn.po
trans.pl = apps/i2ptunnel/locale-proxy/messages_pl.po
trans.pt = apps/i2ptunnel/locale-proxy/messages_pt.po
trans.pt_BR = apps/i2ptunnel/locale-proxy/messages_pt_BR.po
@@ -94,6 +96,7 @@ trans.zh_TW = apps/routerconsole/locale/messages_zh_TW.po
source_file = apps/routerconsole/locale-news/messages_en.po
source_lang = en
trans.ar = apps/routerconsole/locale-news/messages_ar.po
trans.az = apps/routerconsole/locale-news/messages_az.po
trans.cs = apps/routerconsole/locale-news/messages_cs.po
trans.de = apps/routerconsole/locale-news/messages_de.po
trans.el = apps/routerconsole/locale-news/messages_el.po
@@ -128,6 +131,8 @@ trans.zh_TW = apps/routerconsole/locale-news/messages_zh_TW.po
type = PO
source_file = apps/routerconsole/locale-countries/messages_en.po
source_lang = en
trans.ar = apps/routerconsole/locale-countries/messages_ar.po
trans.az = apps/routerconsole/locale-countries/messages_az.po
trans.ca = apps/routerconsole/locale-countries/messages_ca.po
trans.da = apps/routerconsole/locale-countries/messages_da.po
trans.de = apps/routerconsole/locale-countries/messages_de.po
@@ -138,6 +143,7 @@ trans.fa = apps/routerconsole/locale-countries/messages_fa.po
trans.fi = apps/routerconsole/locale-countries/messages_fi.po
trans.fr = apps/routerconsole/locale-countries/messages_fr.po
trans.gl = apps/routerconsole/locale-countries/messages_gl.po
trans.hr = apps/routerconsole/locale-countries/messages_hr.po
trans.hu = apps/routerconsole/locale-countries/messages_hu.po
;; Java converts id to in
trans.id = apps/routerconsole/locale-countries/messages_in.po
@@ -167,6 +173,7 @@ source_lang = en
trans.ar = apps/i2psnark/locale/messages_ar.po
trans.cs = apps/i2psnark/locale/messages_cs.po
trans.de = apps/i2psnark/locale/messages_de.po
trans.el = apps/i2psnark/locale/messages_el.po
trans.es = apps/i2psnark/locale/messages_es.po
trans.fi = apps/i2psnark/locale/messages_fi.po
trans.fr = apps/i2psnark/locale/messages_fr.po
@@ -185,6 +192,7 @@ trans.ro = apps/i2psnark/locale/messages_ro.po
trans.ru_RU = apps/i2psnark/locale/messages_ru.po
trans.sk = apps/i2psnark/locale/messages_sk.po
trans.sv_SE = apps/i2psnark/locale/messages_sv.po
trans.sq = apps/i2psnark/locale/messages_sq.po
trans.tr_TR = apps/i2psnark/locale/messages_tr.po
trans.uk_UA = apps/i2psnark/locale/messages_uk.po
trans.vi = apps/i2psnark/locale/messages_vi.po
@@ -225,6 +233,7 @@ trans.zh_TW = apps/susidns/locale/messages_zh_TW.po
source_file = apps/desktopgui/locale/messages_en.po
source_lang = en
trans.ar = apps/desktopgui/locale/messages_ar.po
trans.az = apps/desktopgui/locale/messages_az.po
trans.bg = apps/desktopgui/locale/messages_bg.po
trans.ca = apps/desktopgui/locale/messages_ca.po
trans.cs = apps/desktopgui/locale/messages_cs.po
@@ -262,6 +271,7 @@ trans.zh_CN = apps/desktopgui/locale/messages_zh.po
source_file = apps/susimail/locale/messages_en.po
source_lang = en
trans.ar = apps/susimail/locale/messages_ar.po
trans.az = apps/susimail/locale/messages_az.po
trans.cs = apps/susimail/locale/messages_cs.po
trans.da = apps/susimail/locale/messages_da.po
trans.de = apps/susimail/locale/messages_de.po
@@ -296,6 +306,8 @@ trans.zh_TW = apps/susimail/locale/messages_zh_TW.po
[I2P.debconf]
source_file = debian/po/templates.pot
source_lang = en
trans.ar = debian/po/ar.po
trans.az = debian/po/az.po
trans.cs = debian/po/cs.po
trans.de = debian/po/de.po
trans.el = debian/po/el.po
@@ -326,6 +338,8 @@ trans.zh_TW = debian/po/zh_TW.po
[I2P.i2prouter-script]
source_file = installer/resources/locale/po/messages_en.po
source_lang = en
trans.ar = installer/resources/locale/po/messages_ar.po
trans.az = installer/resources/locale/po/messages_az.po
trans.ca = installer/resources/locale/po/messages_ca.po
trans.de = installer/resources/locale/po/messages_de.po
trans.es = installer/resources/locale/po/messages_es.po
@@ -335,6 +349,7 @@ trans.id = installer/resources/locale/po/messages_id.po
trans.it = installer/resources/locale/po/messages_it.po
trans.ja = installer/resources/locale/po/messages_ja.po
trans.ko = installer/resources/locale/po/messages_ko.po
trans.nb = installer/resources/locale/po/messages_nb.po
trans.nl = installer/resources/locale/po/messages_nl.po
trans.pl = installer/resources/locale/po/messages_pl.po
trans.pt = installer/resources/locale/po/messages_pt.po
@@ -367,6 +382,8 @@ trans.zh_CN = installer/resources/locale/po/messages_zh.po
source_file = core/java/src/gnu/getopt/MessagesBundle.properties
source_lang = en
type = PROPERTIES
trans.ar = core/java/src/gnu/getopt/MessagesBundle_ar.properties
trans.az = core/java/src/gnu/getopt/MessagesBundle_az.properties
trans.cs = core/java/src/gnu/getopt/MessagesBundle_cs.properties
trans.de = core/java/src/gnu/getopt/MessagesBundle_de.properties
trans.es = core/java/src/gnu/getopt/MessagesBundle_es.properties
@@ -398,6 +415,8 @@ trans.zh_TW = core/java/src/gnu/getopt/MessagesBundle_zh_TW.properties
[I2P.streaming]
source_file = apps/ministreaming/locale/messages_en.po
source_lang = en
trans.ar = apps/ministreaming/locale/messages_ar.po
trans.az = apps/ministreaming/locale/messages_az.po
trans.ca = apps/ministreaming/locale/messages_ca.po
trans.cs = apps/ministreaming/locale/messages_cs.po
trans.de = apps/ministreaming/locale/messages_de.po
@@ -422,10 +441,14 @@ trans.uk_UA = apps/ministreaming/locale/messages_uk.po
trans.zh_CN = apps/ministreaming/locale/messages_zh.po
[I2P.manpages]
;;
;; after adding languages here, add to debian/*.manpages also
;;
type = PO
source_file = installer/resources/locale-man/man.pot
source_lang = en
; after adding languages here, add to debian/*.manpages also
trans.ar = installer/resources/locale-man/man_ar.po
trans.az = installer/resources/locale-man/man_az.po
trans.de = installer/resources/locale-man/man_de.po
trans.es = installer/resources/locale-man/man_es.po
trans.fi = installer/resources/locale-man/man_fi.po
@@ -439,8 +462,57 @@ trans.pt = installer/resources/locale-man/man_pt.po
trans.pt_BR = installer/resources/locale-man/man_pt_BR.po
trans.ru_RU = installer/resources/locale-man/man_ru.po
trans.sv_SE = installer/resources/locale-man/man_sv.po
trans.tr_TR = installer/resources/locale-man/man_tr.po
trans.zh_CN = installer/resources/locale-man/man_zh.po
[I2P.eepsite]
;;
;; For any new translations, add links in index.html,
;; and copy new flags in build.xml copyflags-unlesspkg target,
;; and add to debian/i2p-router.links and debian-alt/*/i2p-router.links
;;
type = HTML
source_file = installer/resources/eepsite/docroot/help/index.html
source_lang = en
trans.ar = installer/resources/eepsite/docroot/help/index_ar.html
trans.az = installer/resources/eepsite/docroot/help/index_az.html
trans.de = installer/resources/eepsite/docroot/help/index_de.html
;; not yet translated on TX, use old page
;;trans.es = installer/resources/eepsite/docroot/help/index_es.html
trans.fr = installer/resources/eepsite/docroot/help/index_fr.html
trans.hu = installer/resources/eepsite/docroot/help/index_hu.html
;; Java converts id to in
trans.id = installer/resources/eepsite/docroot/help/index_in.html
trans.it = installer/resources/eepsite/docroot/help/index_it.html
;; not yet translated on TX, use old page
;;trans.nl = installer/resources/eepsite/docroot/help/index_nl.html
trans.pl = installer/resources/eepsite/docroot/help/index_nl.html
trans.pt = installer/resources/eepsite/docroot/help/index_nl.html
trans.ru_RU = installer/resources/eepsite/docroot/help/index_ru.html
;; not yet translated on TX, use old page
;;trans.sv_SE = installer/resources/eepsite/docroot/help/index_sv.html
trans.tr_TR = installer/resources/eepsite/docroot/help/index_tr.html
;; not yet translated on TX, use old page
;;trans.zh_CN = installer/resources/eepsite/docroot/help/index_zh.html
[I2P.readme]
;;
;; Text on /console
;;
type = HTML
source_file = installer/resources/readme/readme.html
source_lang = en
trans.ar = installer/resources/readme/readme_ar.html
trans.de = installer/resources/readme/readme_de.html
;; Java converts id to in
trans.id = installer/resources/readme/readme_in.html
trans.it = installer/resources/readme/readme_it.html
trans.ja = installer/resources/readme/readme_ja.html
trans.pl = installer/resources/readme/readme_pl.html
trans.pt = installer/resources/readme/readme_pt.html
trans.ru_RU = installer/resources/readme/readme_ru.html
trans.tr_TR = installer/resources/readme/readme_tr.html
[main]
host = https://www.transifex.com

View File

@@ -29,7 +29,7 @@ POSSIBILITY OF SUCH DAMAGES.
LICENSES
--------
Core (i2p.jar):
Core API (i2p.jar):
Public domain except as listed below:
ElGamal and DSA code:
@@ -65,6 +65,7 @@ Public domain except as listed below:
See licenses/LICENSE-HashCash.txt
GettextResource from gettext v0.19.8:
(not included in most distribution packages)
Copyright (C) 2001, 2007 Free Software Foundation, Inc.
See licenses/LICENSE-LGPLv2.1.txt
@@ -72,15 +73,12 @@ Public domain except as listed below:
Contains some code Copyright 2006 Sun Microsystems, Inc.
See licenses/LICENSE-InstallCert.txt
BlockFile:
Copyright (c) 2006, Matthew Estes
See licenses/LICENSE-BlockFile.txt
SipHashInline:
Copyright 2012 Hiroshi Nakamura <nahi@ruby-lang.org>
See licenses/LICENSE-Apache2.0.txt
Getopt:
(not included in most distribution packages)
Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
See licenses/LICENSE-LGPLv2.1.txt
@@ -88,6 +86,14 @@ Public domain except as listed below:
From Apache HttpClient 4.4.1 and HttpCore 4.4.1
See licenses/LICENSE-Apache2.0.txt
json-simple 1.1.1
(not included in most distribution packages)
See licenses/LICENSE-Apache2.0.txt
Noise library:
Copyright (C) 2016 Southern Storm Software, Pty Ltd.
See licenses/LICENSE-Noise.txt
Router (router.jar):
Public domain except as listed below:
@@ -99,15 +105,22 @@ Public domain except as listed below:
Copyright (C) 2003-2010 Satoshi Konno
See licenses/LICENSE-UPnP.txt
GeoIP: GeoLite databases are licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
http://creativecommons.org/licenses/by-sa/3.0/
This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
GeoIP API 1.3.1:
See licenses/LICENSE-LGPLv2.1.txt
GeoIP2-java 2.12.0:
See licenses/LICENSE-Apache2.0.txt
Maxmind-DB-Reader-java 1.2.2:
See licenses/LICENSE-Apache2.0.txt
Noise library:
Copyright (C) 2016 Southern Storm Software, Pty Ltd.
See licenses/LICENSE-Noise.txt
Installer:
(not included in distribution packages)
Launch4j 3.0.1:
(Launch4j is only included in the upstream source package and Windows binaries.
Not applicable for non-Windows binaries or Debian/Launchpad packages.)
@@ -123,7 +136,7 @@ Installer:
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Commons-Logging.txt
XStream (http://xstream.codehaus.org/)
XStream (http://xstream.github.io/)
Copyright (c) 2003-2004, Joe Walnes
See licenses/LICENSE-XStream.txt
@@ -149,14 +162,24 @@ Installer:
See licenses/LICENSE-Apache2.0.txt
GeoIP Data:
(not included in most distribution packages)
This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com/
See licenses/LICENSE-GeoIP.txt
Launchers:
(not included in distribution packages)
Copyright (c) 2002-2018 EPFL, Lausanne / Lightbend, Inc. , unless otherwise specified.
See licenses/LICENSE-Scala.md
Java Service Wrapper Community Edition 32-bit 3.5.34:
(not included in most distribution packages)
Copyright (C) 1999-2017 Tanuki Software, Ltd. All Rights Reserved.
See licenses/LICENSE-Wrapper.txt
Jbigi Libraries (jbigi.jar):
JNI code public domain.
JNI code: public domain.
GMP 4.3.2 / 5.0.2:
Copyright 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc.
@@ -167,41 +190,55 @@ Jbigi Libraries (jbigi.jar):
Applications:
Addressbook:
Addressbook (addressbook.jar):
Copyright (c) 2004 Ragnarok
See licenses/LICENSE-Addressbook.txt
BlockFile:
Copyright (c) 2006, Matthew Estes
See licenses/LICENSE-BlockFile.txt
BOB:
BOB (BOB.jar):
Copyright (C) sponge
See licenses/COPYING-BOB.txt
Desktopgui
Desktopgui (desktopgui.jar):
Copyright (c) Mathias De Maré
See licenses/LICENSE-DesktopGUI.txt
I2PSnark:
Glassfish Standard Tag Library (JSTL) 1.2 (commons-el.jar):
(not included in most distribution packages)
Common Development and Distribution License (CDDL) version 1.0 + GNU General Public License (GPL) version 2
See https://glassfish.dev.java.net/public/CDDL+GPL.html
See licenses/LICENSE-GPLv2.txt
I2PControl
See licenses/LICENSE-Apache2.0.txt
Includes jBCrypt:
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
See licenses/LICENSE-jBCrypt.txt
Includes jsonrpc2 1.38.1 (base) 1.11 (server)
See licenses/LICENSE-Apache2.0.txt
I2PSnark (i2psnark.jar, i2psnark.war):
Copyright (C) 2003 Mark J. Wielaard
GPLv2 (or any later version)
See licenses/LICENSE-GPLv2.txt
Silk icons: See licenses/LICENSE-SilkIcons.txt
I2PTunnel:
I2PTunnel (i2ptunnel.jar, i2ptunnel.war):
(c) 2003 - 2004 mihi
GPLv2 (or any later version) with exception.
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
I2PTunnel SOCKS Proxy:
Copyright (c) 2004 by human
GPLv2 (or any later version) with exception.
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
I2PTunnel UDP and Streamr (i2ptunnel.jar):
By welterde.
See licenses/LICENSE-GPLv2.txt
I2PTunnel SOCKS Proxy:
Copyright (c) 2004 by human
GPLv2 (or any later version) with exception.
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
I2PTunnel UDP and Streamr:
By welterde.
See licenses/LICENSE-GPLv2.txt
Imagegen:
Imagegen (imagegen.war):
Identicon:
Copyright (c) 2007-2014 Don Park <donpark@docuverse.com>
See licenses/LICENSE-Identicon.txt
@@ -212,13 +249,14 @@ Applications:
Zxing 3.3.0:
See licenses/LICENSE-Apache2.0.txt
Jetty 9.2.22.v20170606:
Jetty 9.2.25.v20180606 (jetty-*.jar, org.mortbay.*.jar):
(not included in most distribution packages, except for jetty-i2p.jar)
See licenses/ABOUT-Jetty.html
See licenses/NOTICE-Jetty.html
See licenses/LICENSE-Apache2.0.txt
See licenses/LICENSE-ECLIPSE-1.0.html
JRobin 1.6.0-1:
JRobin 1.6.0-1 (jrobin.jar):
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
Copyright (c) 2011 The OpenNMS Group, Inc.
See licenses/LICENSE-LGPLv2.1.txt
@@ -226,65 +264,64 @@ Applications:
Copyright (c) 2006-2016 Julien Gouesse
See licenses/LICENSE-GPLv2.txt
Ministreaming Lib:
Ministreaming Lib (mstreaming.jar):
By mihi.
See licenses/LICENSE-BSD.txt
Proxyscript:
Proxyscript (i2pProxy.pac):
(not included in distribution packages)
By Cervantes.
Public domain.
Router console:
Router console (routerconsole.jar, routerconsole.war):
Public domain.
Router Console themes:
Flag icons:
- Jersey and EU flag icons: public domain, courtesy Xrmap flag
collection http://www.arvernes.com/wiki/index.php/Xrmap
- Guernsey and Isle of Man flags from the Open Clip Art Library, released into the public domain
- Curaçao, courtesy of David Benbennick, released into the public domain
- All other flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
Silk icons: See licenses/LICENSE-SilkIcons.txt
FatCow icons: See licenses/LICENSE-FatCowIcons.txt
Fugue Icons: See licenses/LICENSE-FugueIcons.txt
GeoIP Data:
This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
See licenses/LICENSE-GeoIP.txt
Feather icons: Copyright (c) 2013-2017 Cole Bemis; see licenses/LICENSE-Feather.txt
Router Console and I2PSnark themes:
"Man with hat over face" & related images licensed under a Creative Commons 2.0 license.
Original photos by Florian Kuhlmann. http://www.flickr.com/photos/floriankuhlmann/3117758155
Some images licensed under a Creative Commons 2.0 license.
Silk icons: See licenses/LICENSE-SilkIcons.txt
I2PSnark light theme:
"Creative Commons Cat" licensed under a Creative Commons Attribution 3.0 Unported License.
Original photo by Boaz Arad. http://www.luxphile.com/2011/01/creative-commons-cat.html
Router Console M-Lab subsystem:
Copyright 2010 Vuze, Inc. All rights reserved.
See licenses/LICENSE-GPLv2.txt
SAM:
Router Console NDT subsystem:
Copyright (c) 2003 University of Chicago. All rights reserved.
See licenses/LICENSE-NDT.txt
Notice: I2P has changed specified portions of the Software, including the package edu.internet2.ndt.
SAM (sam.jar):
Public domain.
Streaming Lib:
Streaming Lib (streaming.jar):
Public domain.
SusiDNS:
SusiDNS (susidns.war):
Copyright (C) 2005 <susi23@mail.i2p>
GPLv2 (or any later version)
See licenses/LICENSE-GPLv2.txt
Uses Glassfish Standard Tag Library (JSTL) 1.2:
Common Development and Distribution License (CDDL) version 1.0 + GNU General Public License (GPL) version 2
See https://glassfish.dev.java.net/public/CDDL+GPL.html
See licenses/LICENSE-GPLv2.txt
SusiMail:
SusiMail (susimail.war):
Copyright (C) 2004-2005 <susi23@mail.i2p>
GPLv2 (or any later version)
See licenses/LICENSE-GPLv2.txt
Systray:
Systray (systray.jar):
Public domain.
Bundles systray4j-2.4.1:
See licenses/LICENSE-LGPLv2.1.txt
Tomcat 8.5.23:
Copyright 1999-2017 The Apache Software Foundation
Tomcat 8.5.40 (jasper-runtime.jar):
(not included in most distribution packages)
Copyright 1999-2019 The Apache Software Foundation
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Tomcat.txt

View File

@@ -17,6 +17,10 @@ FAQ: https://geti2p.net/faq
API: http://docs.i2p-projekt.de/javadoc/
or run 'ant javadoc' then start at build/javadoc/index.html
## How to contribute / Hack on I2P
Please check out [HACKING.md](docs/HACKING.md) and other documents in the docs directory.
## Building packages from source
To get development branch from source control: https://geti2p.net/newdevelopers

View File

@@ -38,6 +38,7 @@ import net.i2p.I2PAppContext;
import net.i2p.app.*;
import net.i2p.client.I2PClient;
import net.i2p.util.I2PAppThread;
import net.i2p.util.PortMapper;
import net.i2p.util.SimpleTimer2;
/**
@@ -131,6 +132,7 @@ public class BOB implements Runnable, ClientApp {
// no longer used.
// private static int maxConnections = 0;
private final I2PAppContext _context;
private final Logger _log;
private final ClientAppManager _mgr;
private final String[] _args;
@@ -158,6 +160,7 @@ public class BOB implements Runnable, ClientApp {
* @since 0.9.10
*/
public BOB(I2PAppContext context, ClientAppManager mgr, String[] args) {
_context = context;
// If we were run from command line, log to stdout
boolean logToStdout = false;
URL classResource = BOB.class.getResource("BOB.class");
@@ -218,7 +221,7 @@ public class BOB implements Runnable, ClientApp {
{
File cfg = new File(configLocation);
if (!cfg.isAbsolute()) {
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
cfg = new File(_context.getConfigDir(), configLocation);
}
FileInputStream fi = null;
try {
@@ -239,7 +242,7 @@ public class BOB implements Runnable, ClientApp {
save = true;
}
if (!props.containsKey(I2PClient.PROP_TCP_PORT)) {
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
props.setProperty(I2PClient.PROP_TCP_PORT, Integer.toString(I2PClient.DEFAULT_LISTEN_PORT));
save = true;
}
if (!props.containsKey(PROP_BOB_PORT)) {
@@ -275,7 +278,7 @@ public class BOB implements Runnable, ClientApp {
if (save) {
File cfg = new File(configLocation);
if (!cfg.isAbsolute()) {
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
cfg = new File(_context.getConfigDir(), configLocation);
}
FileOutputStream fo = null;
try {
@@ -316,6 +319,8 @@ public class BOB implements Runnable, ClientApp {
_log.info("BOB is now running.");
if (_mgr != null)
_mgr.register(this);
_context.portMapper().register(PortMapper.SVC_BOB, props.getProperty(PROP_BOB_HOST),
Integer.parseInt(props.getProperty(PROP_BOB_PORT)));
int i = 0;
boolean g = false;
@@ -353,6 +358,7 @@ public class BOB implements Runnable, ClientApp {
changeState(STOPPING, e);
} finally {
_log.info("BOB is now shutting down...");
_context.portMapper().unregister(PortMapper.SVC_BOB);
// Clean up everything.
try {
listener.close();

View File

@@ -96,12 +96,14 @@ public class MUXlisten implements Runnable {
}
String i2cpHost = Q.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
int i2cpPort = 7654;
String i2cpPortStr = Q.getProperty(I2PClient.PROP_TCP_PORT, "7654");
try {
i2cpPort = Integer.parseInt(i2cpPortStr);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid I2CP port specified [" + i2cpPortStr + "]");
int i2cpPort = I2PClient.DEFAULT_LISTEN_PORT;
String i2cpPortStr = Q.getProperty(I2PClient.PROP_TCP_PORT);
if (i2cpPortStr != null) {
try {
i2cpPort = Integer.parseInt(i2cpPortStr);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid I2CP port specified [" + i2cpPortStr + "]");
}
}
if (this.come_in) {

View File

@@ -176,7 +176,7 @@ class Daemon {
private static void update(NamingService router, Set<String> knownNames,
NamingService publishedNS, AddressBook addressbook,
Iterator<Map.Entry<String, HostTxtEntry>> iter, Log log) {
long start = System.currentTimeMillis();
long start = DEBUG ? System.currentTimeMillis() : 0;
int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
int deleted = 0;
while(iter.hasNext()) {
@@ -189,7 +189,7 @@ class Daemon {
Destination oldDest;
if (knownNames != null) {
oldDest = null;
isKnown = key != null ? knownNames.contains(key) : null;
isKnown = key != null ? knownNames.contains(key) : false;
} else {
oldDest = key != null ? router.lookup(key) : null;
isKnown = oldDest != null;
@@ -803,7 +803,7 @@ class Daemon {
*/
public static void main(String[] args) {
Daemon daemon = new Daemon();
if (args != null && args.length > 0 && args[0].equals("test"))
if (args.length > 0 && args[0].equals("test"))
daemon.test(args);
else
daemon.run(args);
@@ -823,11 +823,14 @@ class Daemon {
ctx.logManager().flush();
}
/**
* @param args may be null
*/
public void run(String[] args) {
_running = true;
String settingsLocation = "config.txt";
File homeFile;
if (args.length > 0) {
if (args != null && args.length > 0) {
homeFile = new SecureDirectory(args[0]);
if (!homeFile.isAbsolute())
homeFile = new SecureDirectory(I2PAppContext.getGlobalContext().getRouterDir(), args[0]);

View File

@@ -590,12 +590,7 @@ public class BlockFile implements Closeable {
_isClosed = true;
metaIndex.close();
Set<String> oi = openIndices.keySet();
Iterator<String> i = oi.iterator();
Object k;
while(i.hasNext()) {
k = i.next();
BSkipList bsl = openIndices.get(k);
for (BSkipList bsl : openIndices.values()) {
bsl.close();
}

View File

@@ -1,99 +0,0 @@
#Last Modified: Sun Dec 06 12:30:32 2015
# vim:syntax=apparmor et ts=8 sw=4
#include <tunables/global>
$INSTALL_PATH/{i2prouter,runplain.sh} flags=(complain) {
#include <abstractions/base>
#include <abstractions/fonts>
#include <abstractions/nameservice>
#include <abstractions/ssl_certs>
capability sys_ptrace,
network inet stream,
network inet6 stream,
$INSTALL_PATH/ r,
$INSTALL_PATH/{i2psvc,wrapper} rmix,
owner $INSTALL_PATH/** rwkm,
# Needed for Java
owner @{PROC} r,
owner @{PROC}/[0-9]*/ r,
owner @{PROC}/[0-9]*/status r,
owner @{PROC}/[0-9]*/stat r,
owner @{PROC}/[0-9]*/cmdline r,
@{PROC}/uptime r,
@{PROC}/sys/kernel/pid_max r,
/sys/devices/system/cpu/ r,
/sys/devices/system/cpu/** r,
/dev/random r,
/dev/urandom r,
@{PROC}/1/comm r,
/etc/ssl/certs/java/** r,
/etc/timezone r,
/usr/share/javazi/** r,
# Debian
/etc/java-{6,7,8}-openjdk/** r,
/usr/lib/jvm/default-java/jre/bin/java rix,
# Debian, Ubuntu, openSUSE
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/java rix,
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/keytool rix,
# Raspbian
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/java rix,
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/keytool rix,
# Fonts are needed for I2P's graphs
/usr/share/java/java-atk-wrapper.jar r,
# Used by some plugins
/usr/share/java/eclipse-ecj-*.jar r,
/{,var/}tmp/ rwm,
owner /{,var/}tmp/** rwkm,
/{,usr/}bin/{,b,d}ash rix,
/{,usr/}bin/cat rix,
/{,usr/}bin/cut rix,
/{,usr/}bin/dirname rix,
/{,usr/}bin/expr rix,
/{,usr/}bin/{,g,m}awk rix,
/{,usr/}bin/grep rix,
/{,usr/}bin/id rix,
/{,usr/}bin/ldd rix,
/{,usr/}bin/ls rix,
/{,usr/}bin/mkdir rix,
/{,usr/}bin/nohup rix,
/{,usr/}bin/ps rix,
/{,usr/}bin/rm rix,
/{,usr/}bin/sed rix,
/{,usr/}bin/sleep rix,
/{,usr/}bin/tail rix,
/{,usr/}bin/tr rix,
/{,usr/}bin/uname rix,
/{,usr/}bin/which rix,
@{HOME}/.java/fonts/** r,
owner @{HOME}/.i2p/ rw,
owner @{HOME}/.i2p/** rwk,
# Prevent spamming the logs
deny owner @{HOME}/.java/ wk,
deny @{HOME}/.fontconfig/ wk,
deny @{HOME}/.java/fonts/** w,
deny /dev/tty rw,
deny /dev/pts/[0-9]* rw,
deny @{PROC}/[0-9]*/fd/ r,
deny /usr/local/share/fonts/ r,
deny /var/cache/fontconfig/ wk,
# Used by some versions of the Tanuki wrapper but never used by I2P
deny /usr/share/java/hamcrest*.jar r,
deny /usr/share/java/junit*.jar r,
}

View File

@@ -10,4 +10,5 @@ dependencies {
compile project(':core')
compile project(':router')
compile project(':installer')
compile project(':apps:systray')
}

View File

@@ -34,6 +34,7 @@
<pathelement location="../../core/java/build/i2p.jar" />
<pathelement location="../../installer/lib/wrapper/all/wrapper.jar" />
<pathelement location="../../router/java/build/router.jar" />
<pathelement location="../systray/java/build/systray.jar" />
</classpath>
</javac>
</target>

View File

@@ -4,6 +4,7 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Ali <aboshanab_@hotmail.com>, 2018
# ducki2p <ducki2p@gmail.com>, 2011
# foo <foo@bar>, 2009
msgid ""
@@ -11,8 +12,8 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"Last-Translator: zzzi2p\n"
"PO-Revision-Date: 2018-05-14 15:25+0000\n"
"Last-Translator: Ali <aboshanab_@hotmail.com>\n"
"Language-Team: Arabic (http://www.transifex.com/otf/I2P/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -43,7 +44,7 @@ msgstr " تشغيل متصفح I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
msgid "Configure I2P System Tray"
msgstr ""
msgstr "تكوين أيقونة I2P المصغرة "
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
@@ -63,17 +64,17 @@ msgstr "توقيف I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
msgid "Restart I2P Immediately"
msgstr ""
msgstr "إعادة تشغيل I2P على الفور"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
msgid "Stop I2P Immediately"
msgstr ""
msgstr "إيقاف تشغيل I2P على الفور"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
msgid "Cancel I2P Shutdown"
msgstr ""
msgstr "إلغاء إيقاف تشغيل I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#, java-format
@@ -92,4 +93,4 @@ msgstr "الشبكة"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
msgid "I2P: Right-click for menu"
msgstr ""
msgstr "I2P: أنقر بالزر الأيمن للقائمة"

View File

@@ -0,0 +1,94 @@
# I2P
# Copyright (C) 2009 The I2P Project
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Nikafn <appone6@gmail.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2018-02-25 16:35+0000\n"
"Last-Translator: Nikafn <appone6@gmail.com>\n"
"Language-Team: Azerbaijani (http://www.transifex.com/otf/I2P/language/az/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: az\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
msgid "Start I2P"
msgstr "I2P Başla"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
msgid "I2P is starting!"
msgstr "I2P başlayır!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
msgid "Starting"
msgstr "Başlanğıc"
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
msgid "Launch I2P Browser"
msgstr "I2P Brauzerini başla"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
msgid "Configure I2P System Tray"
msgstr "I2P Sistem Zolağını quraşdır"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr "Söndür"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
msgid "Restart I2P"
msgstr "I2P yenidən başlat"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
msgid "Stop I2P"
msgstr "I2P-ni durdur"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
msgid "Restart I2P Immediately"
msgstr " I2P-ni dərhal yenidən başlat"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
msgid "Stop I2P Immediately"
msgstr "I2P-ni dərhal durdur"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
msgid "Cancel I2P Shutdown"
msgstr "I2P-ni söndürməyi ləğv et"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#, java-format
msgid "Shutdown in {0}"
msgstr "{0}-da sönmə"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Shutdown imminent"
msgstr "Sönmə yaxınlaşır"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
msgid "Network"
msgstr "Şəbəkə"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
msgid "I2P: Right-click for menu"
msgstr "I2P: Menyu üçün sağ düyməni klikləyin"

View File

@@ -5,13 +5,14 @@
#
# Translators:
# タカハシ <indexial@outlook.jp>, 2013
# Masayuki Hatta <mhatta@mhatta.org>, 2018
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"Last-Translator: zzzi2p\n"
"PO-Revision-Date: 2018-08-17 22:08+0000\n"
"Last-Translator: Masayuki Hatta <mhatta@mhatta.org>\n"
"Language-Team: Japanese (http://www.transifex.com/otf/I2P/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -27,7 +28,7 @@ msgstr "I2P を開始"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
msgid "I2P is starting!"
msgstr "I2P 起動中!"
msgstr "I2P 起動中!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
@@ -42,7 +43,7 @@ msgstr "I2P ブラウザを起動"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
msgid "Configure I2P System Tray"
msgstr ""
msgstr "I2P システムトレイを設定"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
@@ -62,17 +63,17 @@ msgstr "I2P を停止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
msgid "Restart I2P Immediately"
msgstr ""
msgstr "すぐに I2P を再起動"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
msgid "Stop I2P Immediately"
msgstr ""
msgstr "すぐに I2P を停止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
msgid "Cancel I2P Shutdown"
msgstr ""
msgstr "I2P のシャットダウンを中止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#, java-format
@@ -91,4 +92,4 @@ msgstr "ネットワーク"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
msgid "I2P: Right-click for menu"
msgstr ""
msgstr "I2P: 右クリックでメニュー"

View File

@@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"Last-Translator: zzzi2p\n"
"PO-Revision-Date: 2019-05-01 07:33+0000\n"
"Last-Translator: Giovanni Pellerano <giovanni.pellerano@evilaliv3.org>\n"
"Language-Team: Malagasy (http://www.transifex.com/otf/I2P/language/mg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -47,7 +47,7 @@ msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr ""
msgstr "Désactiver"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245

View File

@@ -4,14 +4,14 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Besnik <besnik@programeshqip.org>, 2016
# Besnik <besnik@programeshqip.org>, 2016,2019
# Shpetim <shpetim@privacysolutions.no>, 2014
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"PO-Revision-Date: 2019-01-10 14:28+0000\n"
"Last-Translator: Besnik <besnik@programeshqip.org>\n"
"Language-Team: Albanian (http://www.transifex.com/otf/I2P/language/sq/)\n"
"MIME-Version: 1.0\n"
@@ -92,4 +92,4 @@ msgstr "Rrjet"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
msgid "I2P: Right-click for menu"
msgstr "I2P: Djathtas-klikoni për menu"
msgstr "I2P: Djathtasklikoni për menu"

View File

@@ -6,14 +6,16 @@
# Translators:
# 123hund123 <M8R-ra4r1r@mailinator.com>, 2011
# Anders Nilsson <anders@devode.se>, 2016
# Jony, 2016-2017
# Jonatan Nyberg, 2016-2017
# Jonatan Nyberg, 2018
# Jonatan Nyberg, 2017
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"Last-Translator: Jony\n"
"PO-Revision-Date: 2018-06-17 14:17+0000\n"
"Last-Translator: Jonatan Nyberg\n"
"Language-Team: Swedish (Sweden) (http://www.transifex.com/otf/I2P/language/sv_SE/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -74,7 +76,7 @@ msgstr "Stoppa I2P omedelbart"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
msgid "Cancel I2P Shutdown"
msgstr "Avbryt I2P-avstängning"
msgstr "Avbryt I2P-stängning"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#, java-format
@@ -83,7 +85,7 @@ msgstr "Stänger av om {0}"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Shutdown imminent"
msgstr "Avstängning nära"
msgstr "Stängning nära"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370

View File

@@ -6,16 +6,15 @@ import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingWorker;
import net.i2p.apps.systray.UrlLauncher;
import net.i2p.data.DataHelper;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.desktopgui.util.BrowseException;
import net.i2p.desktopgui.util.I2PDesktop;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.util.PortMapper;
@@ -433,15 +432,16 @@ class InternalTrayManager extends TrayManager {
* and launch the browser at it.
*
* Modified from I2PTunnelHTTPClientBase.
* TODO perhaps move this to a new PortMapper method.
*
* @since 0.9.26
*/
private void launchBrowser() {
// null args ok
UrlLauncher launcher = new UrlLauncher(_context, null, null);
String url = _context.portMapper().getConsoleURL();
try {
I2PDesktop.browse(url);
} catch (BrowseException e1) {
launcher.openUrl(url);
} catch (IOException e1) {
log.log(Log.WARN, "Failed to open browser!", e1);
}
}

View File

@@ -17,7 +17,6 @@ import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.desktopgui.util.*;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
import net.i2p.util.Log;

View File

@@ -1,23 +0,0 @@
package net.i2p.desktopgui.util;
public class BrowseException extends Exception {
private static final long serialVersionUID = 1L;
public BrowseException() {
super();
}
public BrowseException(String s) {
super(s);
}
public BrowseException(String s, Throwable t) {
super(s, t);
}
public BrowseException(Throwable t) {
super(t);
}
}

View File

@@ -1,27 +0,0 @@
package net.i2p.desktopgui.util;
import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.net.URI;
public class I2PDesktop {
public static void browse(String url) throws BrowseException {
if(Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
if(desktop.isSupported(Action.BROWSE)) {
try {
desktop.browse(new URI(url));
} catch (Exception e) {
throw new BrowseException();
}
}
else {
throw new BrowseException();
}
}
else {
throw new BrowseException();
}
}
}

142
apps/i2pcontrol/build.xml Normal file
View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="source">
<property name="i2pbase" value="../.."/>
<property name="i2plib" value="${i2pbase}/build"/>
<property name="jettylib" value="${i2pbase}/apps/jetty/jettylib"/>
<property name="wrapperlib" value="${i2pbase}/installer/lib/wrapper/all"/>
<!--
Supports four build options:
1) war (jsonrpc.war) for running under the console
2) jar (i2pcontrol.jar) for starting and running on its own Jetty instance,
no console dependency
3) socketJar (i2pcontrol.jar) for running on a ServerSocket (JSON splitting),
no Jetty dependency (Work in progress)
4) TODO xxxjar with bundled, small non-Jetty server, similar to I2PTunnelHTTPClient?
-->
<path id="cp">
<pathelement location="${i2plib}/i2p.jar" />
<pathelement location="${i2plib}/router.jar" />
<pathelement location="${jettylib}/org.mortbay.jetty.jar" />
<pathelement location="${jettylib}/javax.servlet.jar" />
<pathelement location="${jettylib}/jetty-servlet.jar" />
<pathelement location="${wrapperlib}/wrapper.jar" />
<!-- following jar only present for debian builds -->
<pathelement location="../../core/java/build/json-simple.jar" />
</path>
<path id="cpSocket">
<pathelement location="${i2plib}/i2p.jar" />
<pathelement location="${i2plib}/router.jar" />
<!-- TODO get rid of wraper dependency also -->
<pathelement location="${wrapperlib}/wrapper.jar" />
<!-- following jar only present for debian builds -->
<pathelement location="../../core/java/build/json-simple.jar" />
</path>
<target name="all" depends="clean, build" />
<target name="build" depends="jar" />
<condition property="depend.available">
<typefound name="depend" />
</condition>
<target name="builddep" if="depend.available">
<depend
cache="${i2pbase}/build"
srcdir="./java"
classpath="${cp}"
destdir="./build/obj" >
</depend>
</target>
<property name="javac.compilerargs" value="" />
<property name="javac.version" value="1.7" />
<target name="compile" depends="builddep" >
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
srcdir="./java"
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
includeAntRuntime="false"
destdir="./build/obj"
classpath="${cp}">
<compilerarg line="${javac.compilerargs}" />
<classpath refid="cp"/>
</javac>
</target>
<!--
More TODO here. jsonrpc2 lib uses MessageContext which depends on servlet
-->
<target name="compileSocketJar" depends="builddep" >
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
sourcepath=""
srcdir="./java"
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
includeAntRuntime="false"
destdir="./build/obj"
classpath="${cpSocket}">
<compilerarg line="${javac.compilerargs}" />
<classpath refid="cpSocket" />
<exclude name="**/I2PControlController.java" />
<exclude name="**/HostCheckHandler.java" />
<exclude name="**/JSONRPC2Servlet.java" />
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
</manifest>
</jar>
</target>
<target name="socketJar" depends="compileSocketJar">
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
</manifest>
</jar>
</target>
<target name="war" depends="compile" >
<war destfile="build/jsonrpc.war" webxml="web.xml" >
<classes dir="./build/obj" excludes="net/i2p/i2pcontrol/I2PControlController.class net/i2p/i2pcontrol/HostCheckHandler.class net/i2p/i2pcontrol/SocketController*.class" />
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
</manifest>
</war>
</target>
<target name="clean">
<delete dir="./build" />
</target>
<target name="cleandep" depends="clean">
</target>
<target name="distclean" depends="clean">
</target>
</project>

View File

@@ -0,0 +1,274 @@
package com.thetransactioncompany.jsonrpc2;
import org.json.simple.JSONObject;
/**
* Represents a JSON-RPC 2.0 error that occurred during the processing of a
* request. This class is immutable.
*
* <p>The protocol expects error objects to be structured like this:
*
* <ul>
* <li>{@code code} An integer that indicates the error type.
* <li>{@code message} A string providing a short description of the
* error. The message should be limited to a concise single sentence.
* <li>{@code data} Additional information, which may be omitted. Its
* contents is entirely defined by the application.
* </ul>
*
* <p>Note that the "Error" word in the class name was put there solely to
* comply with the parlance of the JSON-RPC spec. This class doesn't inherit
* from {@code java.lang.Error}. It's a regular subclass of
* {@code java.lang.Exception} and, if thrown, it's to indicate a condition
* that a reasonable application might want to catch.
*
* <p>This class also includes convenient final static instances for all
* standard JSON-RPC 2.0 errors:
*
* <ul>
* <li>{@link #PARSE_ERROR} JSON parse error (-32700)
* <li>{@link #INVALID_REQUEST} Invalid JSON-RPC 2.0 Request (-32600)
* <li>{@link #METHOD_NOT_FOUND} Method not found (-32601)
* <li>{@link #INVALID_PARAMS} Invalid parameters (-32602)
* <li>{@link #INTERNAL_ERROR} Internal error (-32603)
* </ul>
*
* <p>Note that the range -32099..-32000 is reserved for additional server
* errors.
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2Error extends Exception {
/**
* Serial version UID.
*/
private static final long serialVersionUID = 4682571044532698806L;
/**
* JSON parse error (-32700).
*/
public static final JSONRPC2Error PARSE_ERROR = new JSONRPC2Error(-32700, "JSON parse error");
/**
* Invalid JSON-RPC 2.0 request error (-32600).
*/
public static final JSONRPC2Error INVALID_REQUEST = new JSONRPC2Error(-32600, "Invalid request");
/**
* Method not found error (-32601).
*/
public static final JSONRPC2Error METHOD_NOT_FOUND = new JSONRPC2Error(-32601, "Method not found");
/**
* Invalid parameters error (-32602).
*/
public static final JSONRPC2Error INVALID_PARAMS = new JSONRPC2Error(-32602, "Invalid parameters");
/**
* Internal JSON-RPC 2.0 error (-32603).
*/
public static final JSONRPC2Error INTERNAL_ERROR = new JSONRPC2Error(-32603, "Internal error");
/**
* The error code.
*/
private final int code;
/**
* The optional error data.
*/
private final Object data;
/**
* Appends the specified string to the message of a JSON-RPC 2.0 error.
*
* @param err The JSON-RPC 2.0 error. Must not be {@code null}.
* @param apx The string to append to the original error message.
*
* @return A new JSON-RPC 2.0 error with the appended message.
*/
@Deprecated
public static JSONRPC2Error appendMessage(final JSONRPC2Error err, final String apx) {
return new JSONRPC2Error(err.getCode(), err.getMessage() + apx, err.getData());
}
/**
* Sets the specified data to a JSON-RPC 2.0 error.
*
* @param err The JSON-RPC 2.0 error to have its data field set. Must
* not be {@code null}.
* @param data Optional error data, must <a href="#map">map</a> to a
* valid JSON type.
*
* @return A new JSON-RPC 2.0 error with the set data.
*/
@Deprecated
public static JSONRPC2Error setData(final JSONRPC2Error err, final Object data) {
return new JSONRPC2Error(err.getCode(), err.getMessage(), data);
}
/**
* Creates a new JSON-RPC 2.0 error with the specified code and
* message. The optional data is omitted.
*
* @param code The error code (standard pre-defined or
* application-specific).
* @param message The error message.
*/
public JSONRPC2Error(int code, String message) {
this(code, message, null);
}
/**
* Creates a new JSON-RPC 2.0 error with the specified code,
* message and data.
*
* @param code The error code (standard pre-defined or
* application-specific).
* @param message The error message.
* @param data Optional error data, must <a href="#map">map</a>
* to a valid JSON type.
*/
public JSONRPC2Error(int code, String message, Object data) {
super(message);
this.code = code;
this.data = data;
}
/**
* Gets the JSON-RPC 2.0 error code.
*
* @return The error code.
*/
public int getCode() {
return code;
}
/**
* Gets the JSON-RPC 2.0 error data.
*
* @return The error data, {@code null} if none was specified.
*/
public Object getData() {
return data;
}
/**
* Sets the specified data to a JSON-RPC 2.0 error.
*
* @param data Optional error data, must <a href="#map">map</a> to a
* valid JSON type.
*
* @return A new JSON-RPC 2.0 error with the set data.
*/
public JSONRPC2Error setData(final Object data) {
return new JSONRPC2Error(code, getMessage(), data);
}
/**
* Appends the specified string to the message of this JSON-RPC 2.0
* error.
*
* @param apx The string to append to the original error message.
*
* @return A new JSON-RPC 2.0 error with the appended message.
*/
public JSONRPC2Error appendMessage(final String apx) {
return new JSONRPC2Error(code, getMessage() + apx, data);
}
/**
* @see #toJSONObject
*/
@Deprecated
public JSONObject toJSON() {
return toJSONObject();
}
/**
* Returns a JSON object representation of this JSON-RPC 2.0 error.
*
* @return A JSON object representing this error object.
*/
public JSONObject toJSONObject() {
JSONObject out = new JSONObject();
out.put("code", code);
out.put("message", super.getMessage());
if (data != null)
out.put("data", data);
return out;
}
/**
* Serialises the error object to a JSON string.
*
* @return A JSON-encoded string representing this error object.
*/
@Override
public String toString() {
return toJSON().toString();
}
/**
* Overrides {@code Object.equals()}.
*
* @param object The object to compare to.
*
* @return {@code true} if both objects are instances if this class and
* their error codes are identical, {@code false} if not.
*/
@Override
public boolean equals(Object object) {
return object != null &&
object instanceof JSONRPC2Error &&
code == ((JSONRPC2Error)object).getCode();
}
}

View File

@@ -0,0 +1,251 @@
package com.thetransactioncompany.jsonrpc2;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONAware;
import org.json.simple.JSONObject;
/**
* The base abstract class for JSON-RPC 2.0 requests, notifications and
* responses. Provides common methods for parsing (from JSON string) and
* serialisation (to JSON string) of these three message types.
*
* <p>Example parsing and serialisation back to JSON:
*
* <pre>
* String jsonString = "{\"method\":\"progressNotify\",\"params\":[\"75%\"],\"jsonrpc\":\"2.0\"}";
*
* JSONRPC2Message message = null;
*
* // parse
* try {
* message = JSONRPC2Message.parse(jsonString);
* } catch (JSONRPC2ParseException e) {
* // handle parse exception
* }
*
* if (message instanceof JSONRPC2Request)
* System.out.println("The message is a request");
* else if (message instanceof JSONRPC2Notification)
* System.out.println("The message is a notification");
* else if (message instanceof JSONRPC2Response)
* System.out.println("The message is a response");
*
* // serialise back to JSON string
* System.out.println(message);
*
* </pre>
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
*
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public abstract class JSONRPC2Message implements JSONAware {
/**
* Map of non-standard JSON-RPC 2.0 message attributes, {@code null} if
* none.
*/
private Map <String,Object> nonStdAttributes = null;
/**
* Provides common parsing of JSON-RPC 2.0 requests, notifications
* and responses. Use this method if you don't know which type of
* JSON-RPC message the input JSON string represents.
*
* <p>Batched requests / notifications are not supported.
*
* <p>This method is thread-safe.
*
* <p>If you are certain about the message type use the dedicated
* {@link JSONRPC2Request#parse}, {@link JSONRPC2Notification#parse}
* or {@link JSONRPC2Response#parse} methods. They are more efficient
* and provide a more detailed parse error reporting.
*
* <p>The member order of parsed JSON objects will not be preserved
* (for efficiency reasons) and the JSON-RPC 2.0 version field must be
* set to "2.0". To change this behaviour check the optional {@link
* #parse(String,boolean,boolean)} method.
*
* @param jsonString A JSON string representing a JSON-RPC 2.0 request,
* notification or response, UTF-8 encoded. Must not
* be {@code null}.
*
* @return An instance of {@link JSONRPC2Request},
* {@link JSONRPC2Notification} or {@link JSONRPC2Response}.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Message parse(final String jsonString)
throws JSONRPC2ParseException {
return parse(jsonString, false, false);
}
/**
* Provides common parsing of JSON-RPC 2.0 requests, notifications
* and responses. Use this method if you don't know which type of
* JSON-RPC message the input string represents.
*
* <p>Batched requests / notifications are not supported.
*
* <p>This method is thread-safe.
*
* <p>If you are certain about the message type use the dedicated
* {@link JSONRPC2Request#parse}, {@link JSONRPC2Notification#parse}
* or {@link JSONRPC2Response#parse} methods. They are more efficient
* and provide a more detailed parse error reporting.
*
* @param jsonString A JSON string representing a JSON-RPC 2.0
* request, notification or response, UTF-8
* encoded. Must not be {@code null}.
* @param preserveOrder If {@code true} the member order of JSON objects
* in parameters and results must be preserved.
* @param ignoreVersion If {@code true} the {@code "jsonrpc":"2.0"}
* version field in the JSON-RPC 2.0 message will
* not be checked.
*
* @return An instance of {@link JSONRPC2Request},
* {@link JSONRPC2Notification} or {@link JSONRPC2Response}.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Message parse(final String jsonString, final boolean preserveOrder, final boolean ignoreVersion)
throws JSONRPC2ParseException {
JSONRPC2Parser parser = new JSONRPC2Parser(preserveOrder, ignoreVersion);
return parser.parseJSONRPC2Message(jsonString);
}
/**
* Appends a non-standard attribute to this JSON-RPC 2.0 message. This is
* done by adding a new member (key / value pair) to the top level JSON
* object representing the message.
*
* <p>You may use this method to add meta and debugging attributes,
* such as the request processing time, to a JSON-RPC 2.0 message.
*
* @param name The attribute name. Must not conflict with the existing
* "method", "id", "params", "result", "error" and "jsonrpc"
* attributes reserved by the JSON-RPC 2.0 protocol, else
* an {@code IllegalArgumentException} will be thrown. Must
* not be {@code null} either.
* @param value The attribute value. Must be of type String, boolean,
* number, List, Map or null, else an
* {@code IllegalArgumentException} will be thrown.
*/
public void appendNonStdAttribute(final String name, final Object value) {
// Name check
if (name == null ||
name.equals("method") ||
name.equals("id") ||
name.equals("params") ||
name.equals("result") ||
name.equals("error") ||
name.equals("jsonrpc") )
throw new IllegalArgumentException("Non-standard attribute name violation");
// Value check
if ( value != null &&
! (value instanceof Boolean) &&
! (value instanceof Number) &&
! (value instanceof String) &&
! (value instanceof List) &&
! (value instanceof Map) )
throw new IllegalArgumentException("Illegal non-standard attribute value, must map to a valid JSON type");
if (nonStdAttributes == null)
nonStdAttributes = new HashMap<String,Object>();
nonStdAttributes.put(name, value);
}
/**
* Retrieves a non-standard JSON-RPC 2.0 message attribute.
*
* @param name The name of the non-standard attribute to retrieve. Must
* not be {@code null}.
*
* @return The value of the non-standard attribute (may also be
* {@code null}, {@code null} if not found.
*/
public Object getNonStdAttribute(final String name) {
if (nonStdAttributes == null)
return null;
return nonStdAttributes.get(name);
}
/**
* Retrieves the non-standard JSON-RPC 2.0 message attributes.
*
* @return The non-standard attributes as a map, {@code null} if none.
*/
public Map<String,Object> getNonStdAttributes() {
return nonStdAttributes;
}
/**
* Returns a JSON object representing this JSON-RPC 2.0 message.
*
* @return The JSON object.
*/
public abstract JSONObject toJSONObject();
/**
* Returns a JSON string representation of this JSON-RPC 2.0 message.
*
* @see #toString
*
* @return The JSON object string representing this JSON-RPC 2.0
* message.
*/
public String toJSONString() {
return toString();
}
/**
* Serialises this JSON-RPC 2.0 message to a JSON object string.
*
* @return The JSON object string representing this JSON-RPC 2.0
* message.
*/
@Override
public String toString() {
return toJSONObject().toString();
}
}

View File

@@ -0,0 +1,448 @@
package com.thetransactioncompany.jsonrpc2;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONObject;
/**
* Represents a JSON-RPC 2.0 notification.
*
* <p>Notifications provide a mean for calling a remote procedure without
* generating a response. Note that notifications are inherently unreliable
* as no confirmation is sent back to the caller.
*
* <p>Notifications have the same JSON structure as requests, except that they
* lack an identifier:
* <ul>
* <li>{@code method} The name of the remote method to call.
* <li>{@code params} The required method parameters (if any), which can
* be packed into a JSON array or object.
* <li>{@code jsonrpc} A string indicating the JSON-RPC protocol version
* set to "2.0".
* </ul>
*
* <p>Here is a sample JSON-RPC 2.0 notification string:
*
* <pre>
* {
* "method" : "progressNotify",
* "params" : ["75%"],
* "jsonrpc" : "2.0"
* }
* </pre>
*
* <p>This class provides two methods to obtain a request object:
* <ul>
* <li>Pass a JSON-RPC 2.0 notification string to the static
* {@link #parse} method, or
* <li>Invoke one of the constructors with the appropriate arguments.
* </ul>
*
* <p>Example 1: Parsing a notification string:
*
* <pre>
* String jsonString = "{\"method\":\"progressNotify\",\"params\":[\"75%\"],\"jsonrpc\":\"2.0\"}";
*
* JSONRPC2Notification notification = null;
*
* try {
* notification = JSONRPC2Notification.parse(jsonString);
*
* } catch (JSONRPC2ParseException e) {
* // handle exception
* }
* </pre>
*
* <p>Example 2: Recreating the above request:
*
* <pre>
* String method = "progressNotify";
* List&lt;Object&gt; params = new Vector&lt;Object&gt;();
* params.add("75%");
*
* JSONRPC2Notification notification = new JSONRPC2Notification(method, params);
*
* System.out.println(notification);
* </pre>
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
*
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2Notification extends JSONRPC2Message {
/**
* The requested method name.
*/
private String method;
/**
* The positional parameters, {@code null} if none.
*/
private List<Object> positionalParams;
/**
* The named parameters, {@code null} if none.
*/
private Map<String,Object> namedParams;
/**
* Parses a JSON-RPC 2.0 notification string. This method is
* thread-safe.
*
* @param jsonString The JSON-RPC 2.0 notification string, UTF-8
* encoded. Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 notification object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Notification parse(final String jsonString)
throws JSONRPC2ParseException {
return parse(jsonString, false, false, false);
}
/**
* Parses a JSON-RPC 2.0 notification string. This method is
* thread-safe.
*
* @param jsonString The JSON-RPC 2.0 notification string, UTF-8
* encoded. Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in parameters.
*
* @return The corresponding JSON-RPC 2.0 notification object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Notification parse(final String jsonString,
final boolean preserveOrder)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, false, false);
}
/**
* Parses a JSON-RPC 2.0 notification string. This method is
* thread-safe.
*
* @param jsonString The JSON-RPC 2.0 notification string, UTF-8
* encoded. Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in parameters.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version attribute in the
* JSON-RPC 2.0 message.
*
* @return The corresponding JSON-RPC 2.0 notification object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Notification parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, ignoreVersion, false);
}
/**
* Parses a JSON-RPC 2.0 notification string. This method is
* thread-safe.
*
* @param jsonString The JSON-RPC 2.0 notification string,
* UTF-8 encoded. Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of
* JSON object members in parameters.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version
* attribute in the JSON-RPC 2.0 message.
* @param parseNonStdAttributes {@code true} to parse non-standard
* attributes found in the JSON-RPC 2.0
* message.
*
* @return The corresponding JSON-RPC 2.0 notification object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Notification parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion,
final boolean parseNonStdAttributes)
throws JSONRPC2ParseException {
JSONRPC2Parser parser = new JSONRPC2Parser(preserveOrder, ignoreVersion, parseNonStdAttributes);
return parser.parseJSONRPC2Notification(jsonString);
}
/**
* Constructs a new JSON-RPC 2.0 notification with no parameters.
*
* @param method The name of the requested method. Must not be
* {@code null}.
*/
public JSONRPC2Notification(final String method) {
setMethod(method);
setParams(null);
}
/**
* Constructs a new JSON-RPC 2.0 notification with positional (JSON
* array) parameters.
*
* @param method The name of the requested method. Must not
* be {@code null}.
* @param positionalParams The positional (JSON array) parameters,
* {@code null} if none.
*/
public JSONRPC2Notification(final String method,
final List<Object> positionalParams) {
setMethod(method);
setPositionalParams(positionalParams);
}
/**
* Constructs a new JSON-RPC 2.0 notification with named (JSON object)
* parameters.
*
* @param method The name of the requested method.
* @param namedParams The named (JSON object) parameters, {@code null}
* if none.
*/
public JSONRPC2Notification(final String method,
final Map <String,Object> namedParams) {
setMethod(method);
setNamedParams(namedParams);
}
/**
* Gets the name of the requested method.
*
* @return The method name.
*/
public String getMethod() {
return method;
}
/**
* Sets the name of the requested method.
*
* @param method The method name. Must not be {@code null}.
*/
public void setMethod(final String method) {
// The method name is mandatory
if (method == null)
throw new IllegalArgumentException("The method name must not be null");
this.method = method;
}
/**
* Gets the parameters type ({@link JSONRPC2ParamsType#ARRAY positional},
* {@link JSONRPC2ParamsType#OBJECT named} or
* {@link JSONRPC2ParamsType#NO_PARAMS none}).
*
* @return The parameters type.
*/
public JSONRPC2ParamsType getParamsType() {
if (positionalParams == null && namedParams == null)
return JSONRPC2ParamsType.NO_PARAMS;
if (positionalParams != null)
return JSONRPC2ParamsType.ARRAY;
if (namedParams != null)
return JSONRPC2ParamsType.OBJECT;
else
return JSONRPC2ParamsType.NO_PARAMS;
}
/**
* Gets the notification parameters.
*
* <p>This method was deprecated in version 1.30. Use
* {@link #getPositionalParams} or {@link #getNamedParams} instead.
*
* @return The parameters as {@code List&lt;Object&gt;} for positional
* (JSON array), {@code Map&lt;String,Object&gt;} for named
* (JSON object), or {@code null} if none.
*/
@Deprecated
public Object getParams() {
switch (getParamsType()) {
case ARRAY:
return positionalParams;
case OBJECT:
return namedParams;
default:
return null;
}
}
/**
* Gets the positional (JSON array) parameters.
*
* @since 1.30
*
* @return The positional (JSON array) parameters, {@code null} if none
* or named.
*/
public List<Object> getPositionalParams() {
return positionalParams;
}
/**
* Gets the named parameters.
*
* @since 1.30
*
* @return The named (JSON object) parameters, {@code null} if none or
* positional.
*/
public Map<String,Object> getNamedParams() {
return namedParams;
}
/**
* Sets the notification parameters.
*
* <p>This method was deprecated in version 1.30. Use
* {@link #setPositionalParams} or {@link #setNamedParams} instead.
*
* @param params The parameters. For positional (JSON array) pass a
* {@code List&lt;Object&gt;}. For named (JSON object)
* pass a {@code Map&lt;String,Object&gt;}. If there are
* no parameters pass {@code null}.
*/
@Deprecated
@SuppressWarnings("unchecked")
public void setParams(final Object params) {
if (params == null) {
positionalParams = null;
namedParams = null;
} else if (params instanceof List) {
positionalParams = (List<Object>) params;
} else if (params instanceof Map) {
namedParams = (Map<String, Object>) params;
} else {
throw new IllegalArgumentException("The notification parameters must be of type List, Map or null");
}
}
/**
* Sets the positional (JSON array) request parameters.
*
* @since 1.30
*
* @param positionalParams The positional (JSON array) request
* parameters, {@code null} if none.
*/
public void setPositionalParams(final List<Object> positionalParams) {
if (positionalParams == null)
return;
this.positionalParams = positionalParams;
}
/**
* Sets the named (JSON object) request parameters.
*
* @since 1.30
*
* @param namedParams The named (JSON object) request parameters,
* {@code null} if none.
*/
public void setNamedParams(final Map<String,Object> namedParams) {
if (namedParams == null)
return;
this.namedParams = namedParams;
}
@Override
public JSONObject toJSONObject() {
JSONObject notf = new JSONObject();
notf.put("method", method);
// The params can be omitted if none
switch (getParamsType()) {
case ARRAY:
notf.put("params", positionalParams);
break;
case OBJECT:
notf.put("params", namedParams);
break;
}
notf.put("jsonrpc", "2.0");
Map <String,Object> nonStdAttributes = getNonStdAttributes();
if (nonStdAttributes != null) {
for (final Map.Entry<String,Object> attr: nonStdAttributes.entrySet())
notf.put(attr.getKey(), attr.getValue());
}
return notf;
}
}

View File

@@ -0,0 +1,37 @@
package com.thetransactioncompany.jsonrpc2;
/**
* Enumeration of the three parameter types in JSON-RPC 2.0 requests and
* notifications.
*
* <ul>
* <li>{@link #NO_PARAMS} The method takes no parameters.
* <li>{@link #ARRAY} The method takes positional parameters, packed as a
* JSON array, e.g. {@code ["val1", "val2", ...]}.
* <li>{@link #OBJECT} The method takes named parameters, packed as a JSON
* object, e.g. {@code {"param1":"val1", "param2":"val2", ...}}.
* </ul>
*
* @author Vladimir Dzhuvinov
*/
public enum JSONRPC2ParamsType {
/**
* No parameters.
*/
NO_PARAMS,
/**
* Positional parameters, packed as a JSON array.
*/
ARRAY,
/**
* Named parameters, packed as a JSON object.
*/
OBJECT
}

View File

@@ -0,0 +1,113 @@
package com.thetransactioncompany.jsonrpc2;
/**
* Thrown to indicate an exception during the parsing of a JSON-RPC 2.0
* message string.
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2ParseException extends Exception {
/**
* Serial version UID.
*/
private static final long serialVersionUID = 3376608778436136410L;
/**
* Indicates a parse exception caused by a JSON message not conforming
* to the JSON-RPC 2.0 protocol.
*/
public static final int PROTOCOL = 0;
/**
* Indicates a parse exception caused by invalid JSON.
*/
public static final int JSON = 1;
/**
* The parse exception cause type. Default is {@link #PROTOCOL}.
*/
private int causeType = PROTOCOL;
/**
* The string that could't be parsed.
*/
private String unparsableString = null;
/**
* Creates a new parse exception with the specified message. The cause
* type is set to {@link #PROTOCOL}.
*
* @param message The exception message.
*/
public JSONRPC2ParseException(final String message) {
super(message);
}
/**
* Creates a new parse exception with the specified message and the
* original string that didn't parse. The cause type is set to
* {@link #PROTOCOL}.
*
* @param message The exception message.
* @param unparsableString The unparsable string.
*/
public JSONRPC2ParseException(final String message, final String unparsableString) {
super(message);
this.unparsableString = unparsableString;
}
/**
* Creates a new parse exception with the specified message, cause type
* and the original string that didn't parse.
*
* @param message The exception message.
* @param causeType The exception cause type, either
* {@link #PROTOCOL} or {@link #JSON}.
* @param unparsableString The unparsable string.
*/
public JSONRPC2ParseException(final String message, final int causeType, final String unparsableString) {
super(message);
if (causeType != PROTOCOL && causeType != JSON)
throw new IllegalArgumentException("Cause type must be either PROTOCOL or JSON");
this.causeType = causeType;
this.unparsableString = unparsableString;
}
/**
* Gets the parse exception cause type.
*
* @return The cause type, either {@link #PROTOCOL} or {@link #JSON}.
*/
public int getCauseType() {
return causeType;
}
/**
* Gets original string that caused the parse exception (if specified).
*
* @return The string that didn't parse, {@code null} if none.
*/
public String getUnparsableString() {
return unparsableString;
}
}

View File

@@ -0,0 +1,654 @@
package com.thetransactioncompany.jsonrpc2;
import java.util.List;
import java.util.Map;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/**
* Parses JSON-RPC 2.0 request, notification and response messages.
*
* <p>Parsing of batched requests / notifications is not supported.
*
* <p>This class is not thread-safe. A parser instance should not be used by
* more than one thread unless properly synchronised. Alternatively, you may
* use the thread-safe {@link JSONRPC2Message#parse} and its sister methods.
*
* <p>Example:
*
* <pre>
* String jsonString = "{\"method\":\"makePayment\"," +
* "\"params\":{\"recipient\":\"Penny Adams\",\"amount\":175.05}," +
* "\"id\":\"0001\","+
* "\"jsonrpc\":\"2.0\"}";
*
* JSONRPC2Request req = null;
*
* JSONRPC2Parser parser = new JSONRPC2Parser();
*
* try {
* req = parser.parseJSONRPC2Request(jsonString);
*
* } catch (JSONRPC2ParseException e) {
* // handle exception
* }
*
* </pre>
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
*
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2Parser {
/**
* Reusable JSON parser. Not thread-safe!
*/
private final JSONParser parser;
/**
* If {@code true} the order of the parsed JSON object members must be
* preserved.
*/
private boolean preserveOrder;
/**
* If {@code true} the {@code "jsonrpc":"2.0"} version attribute in the
* JSON-RPC 2.0 message must be ignored during parsing.
*/
private boolean ignoreVersion;
/**
* If {@code true} non-standard JSON-RPC 2.0 message attributes must be
* parsed too.
*/
private boolean parseNonStdAttributes;
/**
* Creates a new JSON-RPC 2.0 message parser.
*
* <p>The member order of parsed JSON objects in parameters and results
* will not be preserved; strict checking of the 2.0 JSON-RPC version
* attribute will be enforced; non-standard message attributes will be
* ignored. Check the other constructors if you want to specify
* different behaviour.
*/
public JSONRPC2Parser() {
this(false, false, false);
}
/**
* Creates a new JSON-RPC 2.0 message parser.
*
* <p>Strict checking of the 2.0 JSON-RPC version attribute will be
* enforced; non-standard message attributes will be ignored. Check the
* other constructors if you want to specify different behaviour.
*
* @param preserveOrder If {@code true} the member order of JSON objects
* in parameters and results will be preserved.
*/
public JSONRPC2Parser(final boolean preserveOrder) {
this(preserveOrder, false, false);
}
/**
* Creates a new JSON-RPC 2.0 message parser.
*
* <p>Non-standard message attributes will be ignored. Check the other
* constructors if you want to specify different behaviour.
*
* @param preserveOrder If {@code true} the member order of JSON objects
* in parameters and results will be preserved.
* @param ignoreVersion If {@code true} the {@code "jsonrpc":"2.0"}
* version attribute in the JSON-RPC 2.0 message
* will not be checked.
*/
public JSONRPC2Parser(final boolean preserveOrder,
final boolean ignoreVersion) {
this(preserveOrder, ignoreVersion, false);
}
/**
* Creates a new JSON-RPC 2.0 message parser.
*
* <p>This constructor allows full specification of the available
* JSON-RPC message parsing properties.
*
* @param preserveOrder If {@code true} the member order of JSON
* objects in parameters and results will
* be preserved.
* @param ignoreVersion If {@code true} the
* {@code "jsonrpc":"2.0"} version
* attribute in the JSON-RPC 2.0 message
* will not be checked.
* @param parseNonStdAttributes If {@code true} non-standard attributes
* found in the JSON-RPC 2.0 messages will
* be parsed too.
*/
public JSONRPC2Parser(final boolean preserveOrder,
final boolean ignoreVersion,
final boolean parseNonStdAttributes) {
// Numbers parsed as long/double, requires JSON Smart 1.0.9+
parser = new JSONParser();
this.preserveOrder = preserveOrder;
this.ignoreVersion = ignoreVersion;
this.parseNonStdAttributes = parseNonStdAttributes;
}
/**
* Parses a JSON object string. Provides the initial parsing of
* JSON-RPC 2.0 messages. The member order of JSON objects will be
* preserved if {@link #preserveOrder} is set to {@code true}.
*
* @param jsonString The JSON string to parse. Must not be
* {@code null}.
*
* @return The parsed JSON object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
@SuppressWarnings("unchecked")
private Map<String,Object> parseJSONObject(final String jsonString)
throws JSONRPC2ParseException {
if (jsonString.trim().length()==0)
throw new JSONRPC2ParseException("Invalid JSON: Empty string",
JSONRPC2ParseException.JSON,
jsonString);
Object json;
// Parse the JSON string
try {
//if (preserveOrder)
// json = parser.parse(jsonString, ContainerFactory.FACTORY_ORDERED);
//else
json = parser.parse(jsonString);
} catch (ParseException e) {
// Terse message, do not include full parse exception message
throw new JSONRPC2ParseException("Invalid JSON",
JSONRPC2ParseException.JSON,
jsonString);
}
if (json instanceof List)
throw new JSONRPC2ParseException("JSON-RPC 2.0 batch requests/notifications not supported", jsonString);
if (! (json instanceof Map))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 message: Message must be a JSON object", jsonString);
return (Map<String,Object>)json;
}
/**
* Ensures the specified parameter is a {@code String} object set to
* "2.0". This method is intended to check the "jsonrpc" attribute
* during parsing of JSON-RPC messages.
*
* @param version The version parameter. Must not be {@code null}.
* @param jsonString The original JSON string.
*
* @throws JSONRPC2ParseException If the parameter is not a string that
* equals "2.0".
*/
private static void ensureVersion2(final Object version, final String jsonString)
throws JSONRPC2ParseException {
if (version == null)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0: Version string missing", jsonString);
else if (! (version instanceof String))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0: Version not a JSON string", jsonString);
else if (! version.equals("2.0"))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0: Version must be \"2.0\"", jsonString);
}
/**
* Provides common parsing of JSON-RPC 2.0 requests, notifications
* and responses. Use this method if you don't know which type of
* JSON-RPC message the input string represents.
*
* <p>If a particular message type is expected use the dedicated
* {@link #parseJSONRPC2Request}, {@link #parseJSONRPC2Notification}
* and {@link #parseJSONRPC2Response} methods. They are more efficient
* and would provide you with more detailed parse error reporting.
*
* @param jsonString A JSON string representing a JSON-RPC 2.0 request,
* notification or response, UTF-8 encoded. Must not
* be {@code null}.
*
* @return An instance of {@link JSONRPC2Request},
* {@link JSONRPC2Notification} or {@link JSONRPC2Response}.
*
* @throws JSONRPC2ParseException With detailed message if the parsing
* failed.
*/
public JSONRPC2Message parseJSONRPC2Message(final String jsonString)
throws JSONRPC2ParseException {
// Try each of the parsers until one succeeds (or all fail)
try {
return parseJSONRPC2Request(jsonString);
} catch (JSONRPC2ParseException e) {
// throw on JSON error, ignore on protocol error
if (e.getCauseType() == JSONRPC2ParseException.JSON)
throw e;
}
try {
return parseJSONRPC2Notification(jsonString);
} catch (JSONRPC2ParseException e) {
// throw on JSON error, ignore on protocol error
if (e.getCauseType() == JSONRPC2ParseException.JSON)
throw e;
}
try {
return parseJSONRPC2Response(jsonString);
} catch (JSONRPC2ParseException e) {
// throw on JSON error, ignore on protocol error
if (e.getCauseType() == JSONRPC2ParseException.JSON)
throw e;
}
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 message",
JSONRPC2ParseException.PROTOCOL,
jsonString);
}
/**
* Parses a JSON-RPC 2.0 request string.
*
* @param jsonString The JSON-RPC 2.0 request string, UTF-8 encoded.
* Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 request object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
@SuppressWarnings("unchecked")
public JSONRPC2Request parseJSONRPC2Request(final String jsonString)
throws JSONRPC2ParseException {
// Initial JSON object parsing
Map<String,Object> jsonObject = parseJSONObject(jsonString);
// Check for JSON-RPC version "2.0"
Object version = jsonObject.remove("jsonrpc");
if (! ignoreVersion)
ensureVersion2(version, jsonString);
// Extract method name
Object method = jsonObject.remove("method");
if (method == null)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Method name missing", jsonString);
else if (! (method instanceof String))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Method name not a JSON string", jsonString);
else if (((String)method).length() == 0)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Method name is an empty string", jsonString);
// Extract ID
if (! jsonObject.containsKey("id"))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Missing identifier", jsonString);
Object id = jsonObject.remove("id");
if ( id != null &&
!(id instanceof Number ) &&
!(id instanceof Boolean) &&
!(id instanceof String ) )
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Identifier not a JSON scalar", jsonString);
// Extract params
Object params = jsonObject.remove("params");
JSONRPC2Request request;
if (params == null)
request = new JSONRPC2Request((String)method, id);
else if (params instanceof List)
request = new JSONRPC2Request((String)method, (List<Object>)params, id);
else if (params instanceof Map)
request = new JSONRPC2Request((String)method, (Map<String,Object>)params, id);
else
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 request: Method parameters have unexpected JSON type", jsonString);
// Extract remaining non-std params?
if (parseNonStdAttributes) {
for (Map.Entry<String,Object> entry: jsonObject.entrySet()) {
request.appendNonStdAttribute(entry.getKey(), entry.getValue());
}
}
return request;
}
/**
* Parses a JSON-RPC 2.0 notification string.
*
* @param jsonString The JSON-RPC 2.0 notification string, UTF-8
* encoded. Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 notification object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
@SuppressWarnings("unchecked")
public JSONRPC2Notification parseJSONRPC2Notification(final String jsonString)
throws JSONRPC2ParseException {
// Initial JSON object parsing
Map<String,Object> jsonObject = parseJSONObject(jsonString);
// Check for JSON-RPC version "2.0"
Object version = jsonObject.remove("jsonrpc");
if (! ignoreVersion)
ensureVersion2(version, jsonString);
// Extract method name
Object method = jsonObject.remove("method");
if (method == null)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 notification: Method name missing", jsonString);
else if (! (method instanceof String))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 notification: Method name not a JSON string", jsonString);
else if (((String)method).length() == 0)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 notification: Method name is an empty string", jsonString);
// Extract params
Object params = jsonObject.get("params");
JSONRPC2Notification notification;
if (params == null)
notification = new JSONRPC2Notification((String)method);
else if (params instanceof List)
notification = new JSONRPC2Notification((String)method, (List<Object>)params);
else if (params instanceof Map)
notification = new JSONRPC2Notification((String)method, (Map<String,Object>)params);
else
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 notification: Method parameters have unexpected JSON type", jsonString);
// Extract remaining non-std params?
if (parseNonStdAttributes) {
for (Map.Entry<String,Object> entry: jsonObject.entrySet()) {
notification.appendNonStdAttribute(entry.getKey(), entry.getValue());
}
}
return notification;
}
/**
* Parses a JSON-RPC 2.0 response string.
*
* @param jsonString The JSON-RPC 2.0 response string, UTF-8 encoded.
* Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 response object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
@SuppressWarnings("unchecked")
public JSONRPC2Response parseJSONRPC2Response(final String jsonString)
throws JSONRPC2ParseException {
// Initial JSON object parsing
Map<String,Object> jsonObject = parseJSONObject(jsonString);
// Check for JSON-RPC version "2.0"
Object version = jsonObject.remove("jsonrpc");
if (! ignoreVersion)
ensureVersion2(version, jsonString);
// Extract request ID
Object id = jsonObject.remove("id");
if ( id != null &&
! (id instanceof Boolean) &&
! (id instanceof Number ) &&
! (id instanceof String ) )
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Identifier not a JSON scalar", jsonString);
// Extract result/error and create response object
// Note: result and error are mutually exclusive
JSONRPC2Response response;
if (jsonObject.containsKey("result") && ! jsonObject.containsKey("error")) {
// Success
Object res = jsonObject.remove("result");
response = new JSONRPC2Response(res, id);
}
else if (! jsonObject.containsKey("result") && jsonObject.containsKey("error")) {
// Error JSON object
Object errorJSON = jsonObject.remove("error");
if (errorJSON == null)
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Missing error object", jsonString);
if (! (errorJSON instanceof Map))
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Error object not a JSON object");
Map<String,Object> error = (Map<String,Object>)errorJSON;
int errorCode;
try {
errorCode = ((Number)error.get("code")).intValue();
} catch (Exception e) {
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Error code missing or not an integer", jsonString);
}
String errorMessage;
try {
errorMessage = (String)error.get("message");
} catch (Exception e) {
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Error message missing or not a string", jsonString);
}
Object errorData = error.get("data");
response = new JSONRPC2Response(new JSONRPC2Error(errorCode, errorMessage, errorData), id);
}
else if (jsonObject.containsKey("result") && jsonObject.containsKey("error")) {
// Invalid response
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: You cannot have result and error at the same time", jsonString);
}
else if (! jsonObject.containsKey("result") && ! jsonObject.containsKey("error")){
// Invalid response
throw new JSONRPC2ParseException("Invalid JSON-RPC 2.0 response: Neither result nor error specified", jsonString);
}
else {
throw new AssertionError();
}
// Extract remaining non-std params?
if (parseNonStdAttributes) {
for (Map.Entry<String,Object> entry: jsonObject.entrySet()) {
response.appendNonStdAttribute(entry.getKey(), entry.getValue());
}
}
return response;
}
/**
* Controls the preservation of JSON object member order in parsed
* JSON-RPC 2.0 messages.
*
* @param preserveOrder {@code true} to preserve the order of JSON
* object members, else {@code false}.
*/
public void preserveOrder(final boolean preserveOrder) {
this.preserveOrder = preserveOrder;
}
/**
* Returns {@code true} if the order of JSON object members in parsed
* JSON-RPC 2.0 messages is preserved, else {@code false}.
*
* @return {@code true} if order is preserved, else {@code false}.
*/
public boolean preservesOrder() {
return preserveOrder;
}
/**
* Specifies whether to ignore the {@code "jsonrpc":"2.0"} version
* attribute during parsing of JSON-RPC 2.0 messages.
*
* <p>You may with to disable strict 2.0 version checking if the parsed
* JSON-RPC 2.0 messages don't include a version attribute or if you
* wish to achieve limited compatibility with older JSON-RPC protocol
* versions.
*
* @param ignore {@code true} to skip checks of the
* {@code "jsonrpc":"2.0"} version attribute in parsed
* JSON-RPC 2.0 messages, else {@code false}.
*/
public void ignoreVersion(final boolean ignore) {
ignoreVersion = ignore;
}
/**
* Returns {@code true} if the {@code "jsonrpc":"2.0"} version
* attribute in parsed JSON-RPC 2.0 messages is ignored, else
* {@code false}.
*
* @return {@code true} if the {@code "jsonrpc":"2.0"} version
* attribute in parsed JSON-RPC 2.0 messages is ignored, else
* {@code false}.
*/
public boolean ignoresVersion() {
return ignoreVersion;
}
/**
* Specifies whether to parse non-standard attributes found in JSON-RPC
* 2.0 messages.
*
* @param enable {@code true} to parse non-standard attributes, else
* {@code false}.
*/
public void parseNonStdAttributes(final boolean enable) {
parseNonStdAttributes = enable;
}
/**
* Returns {@code true} if non-standard attributes in JSON-RPC 2.0
* messages are parsed.
*
* @return {@code true} if non-standard attributes are parsed, else
* {@code false}.
*/
public boolean parsesNonStdAttributes() {
return parseNonStdAttributes;
}
}

View File

@@ -0,0 +1,507 @@
package com.thetransactioncompany.jsonrpc2;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONObject;
/**
* Represents a JSON-RPC 2.0 request.
*
* <p>A request carries four pieces of data:
* <ul>
* <li>{@code method} The name of the remote method to call.
* <li>{@code params} The required method parameters (if any), which can
* be packed into a JSON array or object.
* <li>{@code id} An identifier which is echoed back to the client with
* the response.
* <li>{@code jsonrpc} A string indicating the JSON-RPC protocol version
* set to "2.0".
* </ul>
*
* <p>Here is a sample JSON-RPC 2.0 request string:
*
* <pre>
* {
* "method" : "makePayment",
* "params" : { "recipient" : "Penny Adams", "amount":175.05 },
* "id" : "0001",
* "jsonrpc" : "2.0"
* }
* </pre>
*
* <p>This class provides two methods to obtain a request object:
* <ul>
* <li>Pass a JSON-RPC 2.0 request string to the static
* {@link #parse} method, or
* <li>Invoke one of the constructors with the appropriate arguments.
* </ul>
*
* <p>Example 1: Parsing a request string:
*
* <pre>
* String jsonString = "{\"method\":\"makePayment\"," +
* "\"params\":{\"recipient\":\"Penny Adams\",\"amount\":175.05}," +
* "\"id\":\"0001\","+
* "\"jsonrpc\":\"2.0\"}";
*
* JSONRPC2Request req = null;
*
* try {
* req = JSONRPC2Request.parse(jsonString);
*
* } catch (JSONRPC2ParseException e) {
* // handle exception
* }
* </pre>
*
* <p>Example 2: Recreating the above request:
*
* <pre>
* String method = "makePayment";
* Map&lt;String,Object&gt; params = new HashMap&lt;String,Object&gt;();
* params.put("recipient", "Penny Adams");
* params.put("amount", 175.05);
* String id = "0001";
*
* JSONRPC2Request req = new JSONRPC2Request(method, params, id);
*
* System.out.println(req);
* </pre>
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
*
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2Request extends JSONRPC2Message {
/**
* The method name.
*/
private String method;
/**
* The positional parameters, {@code null} if none.
*/
private List<Object> positionalParams;
/**
* The named parameters, {@code null} if none.
*/
private Map<String,Object> namedParams;
/**
* The request identifier.
*/
private Object id;
/**
* Parses a JSON-RPC 2.0 request string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 request string, UTF-8 encoded.
* Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 request object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Request parse(final String jsonString)
throws JSONRPC2ParseException {
return parse(jsonString, false, false, false);
}
/**
* Parses a JSON-RPC 2.0 request string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 request string, UTF-8 encoded.
* Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in parameters.
*
* @return The corresponding JSON-RPC 2.0 request object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Request parse(final String jsonString,
final boolean preserveOrder)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, false, false);
}
/**
* Parses a JSON-RPC 2.0 request string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 request string, UTF-8 encoded.
* Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in parameters.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version attribute in the
* JSON-RPC 2.0 message.
*
* @return The corresponding JSON-RPC 2.0 request object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Request parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, ignoreVersion, false);
}
/**
* Parses a JSON-RPC 2.0 request string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 request string, UTF-8
* encoded. Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of
* JSON object members in parameters.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version
* attribute in the JSON-RPC 2.0 message.
* @param parseNonStdAttributes {@code true} to parse non-standard
* attributes found in the JSON-RPC 2.0
* message.
*
* @return The corresponding JSON-RPC 2.0 request object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Request parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion,
final boolean parseNonStdAttributes)
throws JSONRPC2ParseException {
JSONRPC2Parser parser = new JSONRPC2Parser(preserveOrder,
ignoreVersion,
parseNonStdAttributes);
return parser.parseJSONRPC2Request(jsonString);
}
/**
* Constructs a new JSON-RPC 2.0 request with no parameters.
*
* @param method The name of the requested method. Must not be
* {@code null}.
* @param id The request identifier echoed back to the caller.
* The value must <a href="#map">map</a> to a JSON
* scalar ({@code null} and fractions, however, should
* be avoided).
*/
public JSONRPC2Request(final String method, final Object id) {
setMethod(method);
setID(id);
}
/**
* Constructs a new JSON-RPC 2.0 request with positional (JSON array)
* parameters.
*
* @param method The name of the requested method. Must not
* be {@code null}.
* @param positionalParams The positional (JSON array) parameters,
* {@code null} if none.
* @param id The request identifier echoed back to the
* caller. The value must <a href="#map">map</a>
* to a JSON scalar ({@code null} and
* fractions, however, should be avoided).
*/
public JSONRPC2Request(final String method,
final List<Object> positionalParams,
final Object id) {
setMethod(method);
setPositionalParams(positionalParams);
setID(id);
}
/**
* Constructs a new JSON-RPC 2.0 request with named (JSON object)
* parameters.
*
* @param method The name of the requested method.
* @param namedParams The named (JSON object) parameters, {@code null}
* if none.
* @param id The request identifier echoed back to the caller.
* The value must <a href="#map">map</a> to a JSON
* scalar ({@code null} and fractions, however,
* should be avoided).
*/
public JSONRPC2Request(final String method,
final Map <String,Object> namedParams,
final Object id) {
setMethod(method);
setNamedParams(namedParams);
setID(id);
}
/**
* Gets the name of the requested method.
*
* @return The method name.
*/
public String getMethod() {
return method;
}
/**
* Sets the name of the requested method.
*
* @param method The method name. Must not be {@code null}.
*/
public void setMethod(final String method) {
// The method name is mandatory
if (method == null)
throw new IllegalArgumentException("The method name must not be null");
this.method = method;
}
/**
* Gets the parameters type ({@link JSONRPC2ParamsType#ARRAY positional},
* {@link JSONRPC2ParamsType#OBJECT named} or
* {@link JSONRPC2ParamsType#NO_PARAMS none}).
*
* @return The parameters type.
*/
public JSONRPC2ParamsType getParamsType() {
if (positionalParams == null && namedParams == null)
return JSONRPC2ParamsType.NO_PARAMS;
if (positionalParams != null)
return JSONRPC2ParamsType.ARRAY;
if (namedParams != null)
return JSONRPC2ParamsType.OBJECT;
else
return JSONRPC2ParamsType.NO_PARAMS;
}
/**
* Gets the request parameters.
*
* <p>This method was deprecated in version 1.30. Use
* {@link #getPositionalParams} or {@link #getNamedParams} instead.
*
* @return The parameters as {@code List&lt;Object&gt;} for positional
* (JSON array), {@code Map&lt;String,Object&gt;} for named
* (JSON object), or {@code null} if none.
*/
@Deprecated
public Object getParams() {
switch (getParamsType()) {
case ARRAY:
return positionalParams;
case OBJECT:
return namedParams;
default:
return null;
}
}
/**
* Gets the positional (JSON array) parameters.
*
* @since 1.30
*
* @return The positional (JSON array) parameters, {@code null} if none
* or named.
*/
public List<Object> getPositionalParams() {
return positionalParams;
}
/**
* Gets the named parameters.
*
* @since 1.30
*
* @return The named (JSON object) parameters, {@code null} if none or
* positional.
*/
public Map<String,Object> getNamedParams() {
return namedParams;
}
/**
* Sets the request parameters.
*
* <p>This method was deprecated in version 1.30. Use
* {@link #setPositionalParams} or {@link #setNamedParams} instead.
*
* @param params The parameters. For positional (JSON array) pass a
* {@code List&lt;Object&gt;}. For named (JSON object)
* pass a {@code Map&lt;String,Object&gt;}. If there are
* no parameters pass {@code null}.
*/
@Deprecated
@SuppressWarnings("unchecked")
public void setParams(final Object params) {
if (params == null) {
positionalParams = null;
namedParams = null;
} else if (params instanceof List) {
positionalParams = (List<Object>) params;
} else if (params instanceof Map) {
namedParams = (Map<String, Object>) params;
} else {
throw new IllegalArgumentException("The request parameters must be of type List, Map or null");
}
}
/**
* Sets the positional (JSON array) request parameters.
*
* @since 1.30
*
* @param positionalParams The positional (JSON array) request
* parameters, {@code null} if none.
*/
public void setPositionalParams(final List<Object> positionalParams) {
if (positionalParams == null)
return;
this.positionalParams = positionalParams;
}
/**
* Sets the named (JSON object) request parameters.
*
* @since 1.30
*
* @param namedParams The named (JSON object) request parameters,
* {@code null} if none.
*/
public void setNamedParams(final Map<String,Object> namedParams) {
if (namedParams == null)
return;
this.namedParams = namedParams;
}
/**
* Gets the request identifier.
*
* @return The request identifier ({@code Number}, {@code Boolean},
* {@code String}) or {@code null}.
*/
public Object getID() {
return id;
}
/**
* Sets the request identifier (ID).
*
* @param id The request identifier echoed back to the caller.
* The value must <a href="#map">map</a> to a JSON
* scalar ({@code null} and fractions, however, should
* be avoided).
*/
public void setID(final Object id) {
if (id == null ||
id instanceof Boolean ||
id instanceof Number ||
id instanceof String
) {
this.id = id;
} else {
this.id = id.toString();
}
}
@Override
public JSONObject toJSONObject() {
JSONObject req = new JSONObject();
req.put("method", method);
// The params can be omitted if none
switch (getParamsType()) {
case ARRAY:
req.put("params", positionalParams);
break;
case OBJECT:
req.put("params", namedParams);
break;
}
req.put("id", id);
req.put("jsonrpc", "2.0");
Map <String,Object> nonStdAttributes = getNonStdAttributes();
if (nonStdAttributes != null) {
for (final Map.Entry<String,Object> attr: nonStdAttributes.entrySet())
req.put(attr.getKey(), attr.getValue());
}
return req;
}
}

View File

@@ -0,0 +1,414 @@
package com.thetransactioncompany.jsonrpc2;
import java.util.Map;
import org.json.simple.JSONObject;
/**
* Represents a JSON-RPC 2.0 response.
*
* <p>A response is returned to the caller after a JSON-RPC 2.0 request has
* been processed (notifications, however, don't produce a response). The
* response can take two different forms depending on the outcome:
*
* <ul>
* <li>The request was successful. The corresponding response returns
* a JSON object with the following information:
* <ul>
* <li>{@code result} The result, which can be of any JSON type
* - a number, a boolean value, a string, an array, an object
* or null.
* <li>{@code id} The request identifier which is echoed back back
* to the caller.
* <li>{@code jsonrpc} A string indicating the JSON-RPC protocol
* version set to "2.0".
* </ul>
* <li>The request failed. The returned JSON object contains:
* <ul>
* <li>{@code error} An object with:
* <ul>
* <li>{@code code} An integer indicating the error type.
* <li>{@code message} A brief error messsage.
* <li>{@code data} Optional error data.
* </ul>
* <li>{@code id} The request identifier. If it couldn't be
* determined, e.g. due to a request parse error, the ID is
* set to {@code null}.
* <li>{@code jsonrpc} A string indicating the JSON-RPC protocol
* version set to "2.0".
* </ul>
* </ul>
*
* <p>Here is an example JSON-RPC 2.0 response string where the request
* has succeeded:
*
* <pre>
* {
* "result" : true,
* "id" : "req-002",
* "jsonrpc" : "2.0"
* }
* </pre>
*
*
* <p>And here is an example JSON-RPC 2.0 response string indicating a failure:
*
* <pre>
* {
* "error" : { "code" : -32601, "message" : "Method not found" },
* "id" : "req-003",
* "jsonrpc" : "2.0"
* }
* </pre>
*
* <p>A response object is obtained either by passing a valid JSON-RPC 2.0
* response string to the static {@link #parse} method or by invoking the
* appropriate constructor.
*
* <p>Here is how parsing is done:
*
* <pre>
* String jsonString = "{\"result\":true,\"id\":\"req-002\",\"jsonrpc\":\"2.0\"}";
*
* JSONRPC2Response response = null;
*
* try {
* response = JSONRPC2Response.parse(jsonString);
*
* } catch (JSONRPC2Exception e) {
* // handle exception
* }
* </pre>
*
* <p>And here is how you can replicate the above example response strings:
*
* <pre>
* // success example
* JSONRPC2Response resp = new JSONRPC2Response(true, "req-002");
* System.out.println(resp);
*
* // failure example
* JSONRPC2Error err = new JSONRPC2Error(-32601, "Method not found");
* resp = new JSONRPC2Response(err, "req-003");
* System.out.println(resp);
*
* </pre>
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON Smart library):
*
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* @author Vladimir Dzhuvinov
*/
public class JSONRPC2Response extends JSONRPC2Message {
/**
* The result.
*/
private Object result = null;
/**
* The error object.
*/
private JSONRPC2Error error = null;
/**
* The echoed request identifier.
*/
private Object id = null;
/**
* Parses a JSON-RPC 2.0 response string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 response string, UTF-8 encoded.
* Must not be {@code null}.
*
* @return The corresponding JSON-RPC 2.0 response object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Response parse(final String jsonString)
throws JSONRPC2ParseException {
return parse(jsonString, false, false, false);
}
/**
* Parses a JSON-RPC 2.0 response string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 response string, UTF-8 encoded.
* Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in results.
*
* @return The corresponding JSON-RPC 2.0 response object.
*
* @throws JSONRPC2ParseException With detailed message if parsing
* failed.
*/
public static JSONRPC2Response parse(final String jsonString,
final boolean preserveOrder)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, false, false);
}
/**
* Parses a JSON-RPC 2.0 response string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 response string, UTF-8 encoded.
* Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of JSON
* object members in results.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version attribute in the
* JSON-RPC 2.0 message.
*
* @return The corresponding JSON-RPC 2.0 response object.
*
* @throws JSONRPC2ParseException With detailed message if the parsing
* failed.
*/
public static JSONRPC2Response parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion)
throws JSONRPC2ParseException {
return parse(jsonString, preserveOrder, ignoreVersion, false);
}
/**
* Parses a JSON-RPC 2.0 response string. This method is thread-safe.
*
* @param jsonString The JSON-RPC 2.0 response string, UTF-8
* encoded. Must not be {@code null}.
* @param preserveOrder {@code true} to preserve the order of
* JSON object members in results.
* @param ignoreVersion {@code true} to skip a check of the
* {@code "jsonrpc":"2.0"} version
* attribute in the JSON-RPC 2.0 message.
* @param parseNonStdAttributes {@code true} to parse non-standard
* attributes found in the JSON-RPC 2.0
* message.
*
* @return The corresponding JSON-RPC 2.0 response object.
*
* @throws JSONRPC2ParseException With detailed message if the parsing
* failed.
*/
public static JSONRPC2Response parse(final String jsonString,
final boolean preserveOrder,
final boolean ignoreVersion,
final boolean parseNonStdAttributes)
throws JSONRPC2ParseException {
JSONRPC2Parser parser = new JSONRPC2Parser(preserveOrder, ignoreVersion, parseNonStdAttributes);
return parser.parseJSONRPC2Response(jsonString);
}
/**
* Creates a new JSON-RPC 2.0 response to a successful request.
*
* @param result The result. The value can <a href="#map">map</a>
* to any JSON type. May be {@code null}.
* @param id The request identifier echoed back to the caller. May
* be {@code null} though not recommended.
*/
public JSONRPC2Response(final Object result, final Object id) {
setResult(result);
setID(id);
}
/**
* Creates a new JSON-RPC 2.0 response to a successful request which
* result is {@code null}.
*
* @param id The request identifier echoed back to the caller. May be
* {@code null} though not recommended.
*/
public JSONRPC2Response(final Object id) {
setResult(null);
setID(id);
}
/**
* Creates a new JSON-RPC 2.0 response to a failed request.
*
* @param error A JSON-RPC 2.0 error instance indicating the
* cause of the failure. Must not be {@code null}.
* @param id The request identifier echoed back to the caller.
* Pass a {@code null} if the request identifier couldn't
* be determined (e.g. due to a parse error).
*/
public JSONRPC2Response(final JSONRPC2Error error, final Object id) {
setError(error);
setID(id);
}
/**
* Indicates a successful JSON-RPC 2.0 request and sets the result.
* Note that if the response was previously indicating failure this
* will turn it into a response indicating success. Any previously set
* error data will be invalidated.
*
* @param result The result. The value can <a href="#map">map</a> to
* any JSON type. May be {@code null}.
*/
public void setResult(final Object result) {
// result and error are mutually exclusive
this.result = result;
this.error = null;
}
/**
* Gets the result of the request. The returned value has meaning
* only if the request was successful. Use the
* {@link #getError getError} method to check this.
*
* @return The result.
*/
public Object getResult() {
return result;
}
/**
* Indicates a failed JSON-RPC 2.0 request and sets the error details.
* Note that if the response was previously indicating success this
* will turn it into a response indicating failure. Any previously set
* result data will be invalidated.
*
* @param error A JSON-RPC 2.0 error instance indicating the cause of
* the failure. Must not be {@code null}.
*/
public void setError(final JSONRPC2Error error) {
if (error == null)
throw new IllegalArgumentException("The error object cannot be null");
// result and error are mutually exclusive
this.error = error;
this.result = null;
}
/**
* Gets the error object indicating the cause of the request failure.
* If a {@code null} is returned, the request succeeded and there was
* no error.
*
* @return A JSON-RPC 2.0 error object, {@code null} if the response
* indicates success.
*/
public JSONRPC2Error getError() {
return error;
}
/**
* A convinience method to check if the response indicates success or
* failure of the request. Alternatively, you can use the
* {@code #getError} method for this purpose.
*
* @return {@code true} if the request succeeded, {@code false} if
* there was an error.
*/
public boolean indicatesSuccess() {
return error == null;
}
/**
* Sets the request identifier echoed back to the caller.
*
* @param id The value must <a href="#map">map</a> to a JSON scalar.
* Pass a {@code null} if the request identifier couldn't
* be determined (e.g. due to a parse error).
*/
public void setID(final Object id) {
if (id == null ||
id instanceof Boolean ||
id instanceof Number ||
id instanceof String
) {
this.id = id;
} else {
this.id = id.toString();
}
}
/**
* Gets the request identifier that is echoed back to the caller.
*
* @return The request identifier. If there was an error during the
* the request retrieval (e.g. parse error) and the identifier
* couldn't be determined, the value will be {@code null}.
*/
public Object getID() {
return id;
}
@Override
public JSONObject toJSONObject() {
JSONObject out = new JSONObject();
// Result and error are mutually exclusive
if (error != null) {
out.put("error", error.toJSONObject());
}
else {
out.put("result", result);
}
out.put("id", id);
out.put("jsonrpc", "2.0");
Map <String,Object> nonStdAttributes = getNonStdAttributes();
if (nonStdAttributes != null) {
for (final Map.Entry<String,Object> attr: nonStdAttributes.entrySet())
out.put(attr.getKey(), attr.getValue());
}
return out;
}
}

View File

@@ -0,0 +1,32 @@
/**
* Classes to represent, parse and serialise JSON-RPC 2.0 requests,
* notifications and responses.
*
* <p>JSON-RPC is a protocol for
* <a href="http://en.wikipedia.org/wiki/Remote_procedure_call">remote
* procedure calls</a> (RPC) using <a href="http://www.json.org" >JSON</a>
* - encoded requests and responses. It can be easily relayed over HTTP
* and is of JavaScript origin, making it ideal for use in dynamic web
* applications in the spirit of Ajax and Web 2.0.
*
* <p>This package implements <b>version 2.0</b> of the protocol, with the
* exception of <i>batching / multicall</i>. This feature is deliberately left
* out as it tends to confuse users (judging by posts in the JSON-RPC forum).
*
* <p>See the <a href="http://www.jsonrpc.org/specification"></a>JSON-RPC 2.0
* specification</a> for more information or write to the
* <a href="https://groups.google.com/forum/#!forum/json-rpc">user group</a> if
* you have questions.
*
* <p><b>Package dependencies:</b> The classes in this package rely on the
* {@code org.json.simple} and {@code org.json.simple.parser} packages
* (version 1.1.1 and compabile) for JSON encoding and decoding. You can obtain
* them from the <a href="http://code.google.com/p/json-smart/">JSON-Smart</a>
* website.
*
* @author Vladimir Dzhuvinov
*/
package com.thetransactioncompany.jsonrpc2;

View File

@@ -0,0 +1,263 @@
package com.thetransactioncompany.jsonrpc2.server;
import java.util.Hashtable;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Notification;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
/**
* Dispatcher for JSON-RPC 2.0 requests and notifications. This class is
* tread-safe.
*
* <p>Use the {@code register()} methods to add a request or notification
* handler for an RPC method.
*
* <p>Use the {@code process()} methods to have an incoming request or
* notification processed by the matching handler.
*
* <p>The {@code reportProcTime()} method enables reporting of request
* processing time (in microseconds) by appending a non-standard "xProcTime"
* attribute to the resulting JSON-RPC 2.0 response message.
*
* <p>Example:
*
* <pre>
* {
* "result" : "xyz",
* "id" : 1,
* "jsonrpc" : "2.0",
* "xProcTime" : "189 us"
* }
* </pre>
*
* <p>Note: The dispatch(...) methods were deprecated in version 1.7. Use
* process(...) instead.
*
* @author Vladimir Dzhuvinov
*/
public class Dispatcher implements RequestHandler, NotificationHandler {
/**
* Hashtable of request name / handler pairs.
*/
private final Hashtable<String,RequestHandler> requestHandlers;
/**
* Hashtable of notification name / handler pairs.
*/
private final Hashtable<String,NotificationHandler> notificationHandlers;
/**
* Controls reporting of request processing time by appending a
* non-standard "xProcTime" attribute to the JSON-RPC 2.0 response.
*/
private boolean reportProcTime = false;
/**
* Creates a new dispatcher with no registered handlers.
*/
public Dispatcher() {
requestHandlers = new Hashtable<String,RequestHandler>();
notificationHandlers = new Hashtable<String,NotificationHandler>();
}
/**
* Registers a new JSON-RPC 2.0 request handler.
*
* @param handler The request handler to register. Must not be
* {@code null}.
*
* @throws IllegalArgumentException On attempting to register a handler
* that duplicates an existing request
* name.
*/
public void register(final RequestHandler handler) {
for (String name: handler.handledRequests()) {
if (requestHandlers.containsKey(name))
throw new IllegalArgumentException("Cannot register a duplicate JSON-RPC 2.0 handler for request " + name);
requestHandlers.put(name, handler);
}
}
/**
* Registers a new JSON-RPC 2.0 notification handler.
*
* @param handler The notification handler to register. Must not be
* {@code null}.
*
* @throws IllegalArgumentException On attempting to register a handler
* that duplicates an existing
* notification name.
*/
public void register(final NotificationHandler handler) {
for (String name: handler.handledNotifications()) {
if (notificationHandlers.containsKey(name))
throw new IllegalArgumentException("Cannot register a duplicate JSON-RPC 2.0 handler for notification " + name);
notificationHandlers.put(name, handler);
}
}
@Override
public String[] handledRequests() {
java.util.Set<String> var = requestHandlers.keySet();
return var.toArray(new String[var.size()]);
}
@Override
public String[] handledNotifications() {
java.util.Set<String> var = notificationHandlers.keySet();
return var.toArray(new String[var.size()]);
}
/**
* Gets the handler for the specified JSON-RPC 2.0 request name.
*
* @param requestName The request name to lookup.
*
* @return The corresponding request handler or {@code null} if none
* was found.
*/
public RequestHandler getRequestHandler(final String requestName) {
return requestHandlers.get(requestName);
}
/**
* Gets the handler for the specified JSON-RPC 2.0 notification name.
*
* @param notificationName The notification name to lookup.
*
* @return The corresponding notification handler or {@code null} if
* none was found.
*/
public NotificationHandler getNotificationHandler(final String notificationName) {
return notificationHandlers.get(notificationName);
}
/**
* @deprecated
*/
public JSONRPC2Response dispatch(final JSONRPC2Request request, final MessageContext requestCtx) {
return process(request, requestCtx);
}
@Override
public JSONRPC2Response process(final JSONRPC2Request request, final MessageContext requestCtx) {
long startNanosec = 0;
// Measure request processing time?
if (reportProcTime)
startNanosec = System.nanoTime();
final String method = request.getMethod();
RequestHandler handler = getRequestHandler(method);
if (handler == null) {
// We didn't find a handler for the requested RPC
Object id = request.getID();
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, id);
}
// Process the request
JSONRPC2Response response = handler.process(request, requestCtx);
if (reportProcTime) {
final long procTimeNanosec = System.nanoTime() - startNanosec;
response.appendNonStdAttribute("xProcTime", procTimeNanosec / 1000 + " us");
}
return response;
}
/**
* @deprecated
*/
public void dispatch(final JSONRPC2Notification notification, final MessageContext notificationCtx) {
process(notification, notificationCtx);
}
@Override
public void process(final JSONRPC2Notification notification, final MessageContext notificationCtx) {
final String method = notification.getMethod();
NotificationHandler handler = getNotificationHandler(method);
if (handler == null) {
// We didn't find a handler for the requested RPC
return;
}
// Process the notification
handler.process(notification, notificationCtx);
}
/**
* Controls reporting of request processing time by appending a
* non-standard "xProcTime" attribute to the JSON-RPC 2.0 response.
* Reporting is disabled by default.
*
* @param enable {@code true} to enable proccessing time reporting,
* {@code false} to disable it.
*/
public void reportProcTime(final boolean enable) {
reportProcTime = enable;
}
/**
* Returns {@code true} if reporting of request processing time is
* enabled. See the {@link #reportProcTime} description for more
* information.
*
* @return {@code true} if reporting of request processing time is
* enabled, else {@code false}.
*/
public boolean reportsProcTime() {
return reportProcTime;
}
}

View File

@@ -0,0 +1,428 @@
package com.thetransactioncompany.jsonrpc2.server;
import java.net.InetAddress;
import java.net.URLConnection;
import java.security.Principal;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
/**
* Context information about JSON-RPC 2.0 request and notification messages.
* This class is immutable.
*
* <ul>
* <li>The client's host name.
* <li>The client's IP address.
* <li>Whether the request / notification was transmitted securely (e.g.
* via HTTPS).
* <li>The client principal(s) (user), if authenticated.
* </ul>
*
* @author Vladimir Dzhuvinov
*/
public class MessageContext {
/**
* The client hostname, {@code null} if none was specified.
*/
private String clientHostName = null;
/**
* The client IP address, {@code null} if none was specified.
*/
private String clientInetAddress = null;
/**
* Indicates whether the request was received over a secure channel
* (typically HTTPS).
*/
private boolean secure = false;
/**
* The authenticated client principals, {@code null} if none were
* specified.
*/
private Principal[] principals = null;
/**
* Minimal implementation of the {@link java.security.Principal}
* interface.
*/
public class BasicPrincipal implements Principal {
/**
* The principal name.
*/
private String name;
/**
* Creates a new principal.
*
* @param name The principal name, must not be {@code null} or
* empty string.
*
* @throws IllegalArgumentException On a {@code null} or empty
* principal name.
*/
public BasicPrincipal(final String name) {
if (name == null || name.trim().isEmpty())
throw new IllegalArgumentException("The principal name must be defined");
this.name = name;
}
/**
* Checks for equality.
*
* @param another The object to compare to.
*/
public boolean equals(final Object another) {
return another != null &&
another instanceof Principal &&
((Principal)another).getName().equals(this.getName());
}
/**
* Returns a hash code for this principal.
*
* @return The hash code.
*/
public int hashCode() {
return getName().hashCode();
}
/**
* Returns the principal name.
*
* @return The principal name.
*/
public String getName() {
return name;
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
* @param principalName Specifies the authenticated client principle
* name, {@code null} if unknown. The name must
* not be an empty or blank string.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure,
final String principalName) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
if (principalName != null) {
principals = new Principal[1];
principals[0] = new BasicPrincipal(principalName);
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
* @param principalNames Specifies the authenticated client principle
* names, {@code null} if unknown. The names
* must not be an empty or blank string.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure,
final String[] principalNames) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
if (principalNames != null) {
principals = new Principal[principalNames.length];
for (int i=0; i < principals.length; i++)
principals[0] = new BasicPrincipal(principalNames[i]);
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. No
* authenticated client principal is specified.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
* @param secure Specifies a request received over HTTPS.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress,
final boolean secure) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = secure;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. Indicates
* an insecure transport (plain HTTP) and no authenticated client
* principal.
*
* @param clientHostName The client host name, {@code null} if
* unknown.
* @param clientInetAddress The client IP address, {@code null} if
* unknown.
*/
public MessageContext(final String clientHostName,
final String clientInetAddress) {
this.clientHostName = clientHostName;
this.clientInetAddress = clientInetAddress;
this.secure = false;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context. Indicates
* an insecure transport (plain HTTP) and no authenticated client
* principal. Not client host name / IP is specified.
*/
public MessageContext() {
this.secure = false;
}
/**
* Creates a new JSON-RPC 2.0 request / notification context from the
* specified HTTP request.
*
* @param httpRequest The HTTP request.
*/
public MessageContext(final HttpServletRequest httpRequest) {
clientInetAddress = httpRequest.getRemoteAddr();
clientHostName = httpRequest.getRemoteHost();
if (clientHostName != null && clientHostName.equals(clientInetAddress))
clientHostName = null; // not resolved actually
secure = httpRequest.isSecure();
X509Certificate[] certs = (X509Certificate[])httpRequest.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null && certs.length > 0) {
principals = new Principal[certs.length];
for (int i=0; i < principals.length; i++)
principals[i] = certs[i].getSubjectX500Principal();
}
}
/**
* Creates a new JSON-RPC 2.0 request / notification context from the
* specified URL connection. Use this constructor in cases when the
* HTTP server is the origin of the JSON-RPC 2.0 requests /
* notifications. If the IP address of the HTTP server cannot be
* resolved {@link #getClientInetAddress} will return {@code null}.
*
* @param connection The URL connection, must be established and not
* {@code null}.
*/
public MessageContext(final URLConnection connection) {
clientHostName = connection.getURL().getHost();
InetAddress ip = null;
if (clientHostName != null) {
try {
ip = InetAddress.getByName(clientHostName);
} catch (Exception e) {
// UnknownHostException, SecurityException
// ignore
}
}
if (ip != null)
clientInetAddress = ip.getHostAddress();
if (connection instanceof HttpsURLConnection) {
secure = true;
HttpsURLConnection httpsConnection = (HttpsURLConnection)connection;
Principal prn = null;
try {
prn = httpsConnection.getPeerPrincipal();
} catch (Exception e) {
// SSLPeerUnverifiedException, IllegalStateException
// ignore
}
if (prn != null) {
principals = new Principal[1];
principals[0] = prn;
}
}
}
/**
* Gets the host name of the client that sent the request /
* notification.
*
* @return The client host name, {@code null} if unknown.
*/
public String getClientHostName() {
return clientHostName;
}
/**
* Gets the IP address of the client that sent the request /
* notification.
*
* @return The client IP address, {@code null} if unknown.
*/
public String getClientInetAddress() {
return clientInetAddress;
}
/**
* Indicates whether the request / notification was received over a
* secure HTTPS connection.
*
* @return {@code true} If the request was received over HTTPS,
* {@code false} if it was received over plain HTTP.
*/
public boolean isSecure() {
return secure;
}
/**
* Returns the first authenticated client principal, {@code null} if
* none.
*
* @return The first client principal, {@code null} if none.
*/
public Principal getPrincipal() {
if (principals != null)
return principals[0];
else
return null;
}
/**
* Returns the authenticated client principals, {@code null} if
* none.
*
* @return The client principals, {@code null} if none.
*/
public Principal[] getPrincipals() {
return principals;
}
/**
* Returns the first authenticated client principal name, {@code null}
* if none.
*
* @return The first client principal name, {@code null} if none.
*/
public String getPrincipalName() {
if (principals != null)
return principals[0].getName();
else
return null;
}
/**
* Returns the authenticated client principal names, {@code null}
* if none.
*
* @return The client principal names, {@code null} if none.
*/
public String[] getPrincipalNames() {
String[] names = new String[principals.length];
for (int i=0; i < names.length; i++)
names[i] = principals[i].getName();
return names;
}
@Override
public String toString() {
String s = "[host=" + clientHostName + " hostIP=" + clientInetAddress + " secure=" + secure;
if (principals != null) {
int i = 0;
for (Principal p: principals)
s += " principal[" + (i++) + "]=" + p;
}
return s + "]";
}
}

View File

@@ -0,0 +1,35 @@
package com.thetransactioncompany.jsonrpc2.server;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Notification;
/**
* Interface for handling JSON-RPC 2.0 notifications.
*
* @author Vladimir Dzhuvinov
*/
public interface NotificationHandler {
/**
* Gets the names of the handled JSON-RPC 2.0 notification methods.
*
* @return The names of the handled JSON-RPC 2.0 notification methods.
*/
public String[] handledNotifications();
/**
* Processes a JSON-RPC 2.0 notification.
*
* <p>Note that JSON-RPC 2.0 notifications don't produce a response!
*
* @param notification A valid JSON-RPC 2.0 notification instance.
* Must not be {@code null}.
* @param notificationCtx Context information about the notification
* message, may be {@code null} if undefined.
*/
public void process(final JSONRPC2Notification notification, final MessageContext notificationCtx);
}

View File

@@ -0,0 +1,36 @@
package com.thetransactioncompany.jsonrpc2.server;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
/**
* Interface for handling JSON-RPC 2.0 requests.
*
* @author Vladimir Dzhuvinov
*/
public interface RequestHandler {
/**
* Gets the names of the handled JSON-RPC 2.0 request methods.
*
* @return The names of the handled JSON-RPC 2.0 request methods.
*/
public String[] handledRequests();
/**
* Processes a JSON-RPC 2.0 request.
*
* @param request A valid JSON-RPC 2.0 request instance. Must not be
* {@code null}.
* @param requestCtx Context information about the request message, may
* be {@code null} if undefined.
*
* @return The resulting JSON-RPC 2.0 response. It indicates success
* or an error, such as METHOD_NOT_FOUND.
*/
public JSONRPC2Response process(final JSONRPC2Request request, final MessageContext requestCtx);
}

View File

@@ -0,0 +1,34 @@
/**
* Simple server framework for processing JSON-RPC 2.0 requests and
* notifications.
*
* <p>Usage:
*
* <ol>
* <li>Implement {@link com.thetransactioncompany.jsonrpc2.server.RequestHandler request}
* and / or {@link com.thetransactioncompany.jsonrpc2.server.NotificationHandler notification}
* handlers for the various expected JSON-RPC 2.0 messages. A handler
* may process one or more request/notification methods (identified by
* method name).
* <li>Create a new {@link com.thetransactioncompany.jsonrpc2.server.Dispatcher}
* and register the handlers with it.
* <li>Pass the received JSON-RPC 2.0 requests and notifications to the
* appropriate {@code Dispatcher.dispatch(...)} method, then, if the
* message is a request, pass the resulting JSON-RPC 2.0 response back
* to the client.
* </ol>
*
* <p>Direct package dependencies:
*
* <ul>
* <li><b><a href="http://software.dzhuvinov.com/json-rpc-2.0-base.html">JSON-RPC 2.0 Base</a></b>
* [<i>com.thetransactioncompany.jsonrpc2</i>] to construct and represent
* JSON-RPC 2.0 messages.
* <li><b>Java Servlet API</b> [<i>javax.servlet.http</i>] for constructing
* {@link com.thetransactioncompany.jsonrpc2.server.MessageContext}
* objects from HTTP servlet requests.
* </ul>
*
* @author Vladimir Dzhuvinov
*/
package com.thetransactioncompany.jsonrpc2.server;

View File

@@ -0,0 +1,80 @@
package com.thetransactioncompany.jsonrpc2.util;
/**
* The base abstract class for the JSON-RPC 2.0 parameter retrievers.
*
* @author Vladimir Dzhuvinov
*/
public abstract class ParamsRetriever {
/**
* Returns the parameter count.
*
* @return The parameters count.
*/
public abstract int size();
/**
* Matches a string against an array of acceptable values.
*
* @param input The string to match.
* @param enumStrings The acceptable string values. Must not be
* {@code null}.
* @param ignoreCase {@code true} for a case insensitive match.
*
* @return The matching string value, {@code null} if no match was
* found.
*/
protected static String getEnumStringMatch(final String input,
final String[] enumStrings,
final boolean ignoreCase) {
for (final String en: enumStrings) {
if (ignoreCase) {
if (en.equalsIgnoreCase(input))
return en;
}
else {
if (en.equals(input))
return en;
}
}
return null;
}
/**
* Matches a string against an enumeration of acceptable values.
*
* @param input The string to match.
* @param enumClass The enumeration class specifying the acceptable
* string values. Must not be {@code null}.
* @param ignoreCase {@code true} for a case insensitive match.
*
* @return The matching enumeration constant, {@code null} if no match
* was found.
*/
protected static <T extends Enum<T>> T getEnumStringMatch(final String input,
final Class<T> enumClass,
final boolean ignoreCase) {
for (T en: enumClass.getEnumConstants()) {
if (ignoreCase) {
if (en.toString().equalsIgnoreCase(input))
return en;
}
else {
if (en.toString().equals(input))
return en;
}
}
return null;
}
}

View File

@@ -0,0 +1,44 @@
/**
* Utility classes for typed retrieval of JSON-RPC 2.0 request parameters on the
* server side.
*
* <p>The following parameter type conversion choices are available:
*
* <ul>
* <li>JSON true/false to Java {@code boolean}
* <li>JSON number to Java {@code int}, {@code long}, {@code float} or
* {@code double}
* <li>JSON string to {@code java.lang.String}
* <li>Predefined (enumerated) JSON string to a Java {@code enum} constant
* or {@code java.lang.String}
* <li>JSON array to Java {@code boolean[]}, {@code int[]}, {@code long[]},
* {@code float[]}, {@code double[]} or {@code string[]} array, or
* to mixed type {@code java.util.List}
* <li>JSON object to {@code java.util.Map}
* </ul>
*
* <p>If a parameter cannot be retrieved, either because it's missing or
* is of the wrong type, a standard
* {@link com.thetransactioncompany.jsonrpc2.JSONRPC2Error#INVALID_PARAMS}
* exception is thrown.
*
* <p>There are two concrete classes:
*
* <ul>
* <li>The {@link com.thetransactioncompany.jsonrpc2.util.PositionalParamsRetriever}
* class is for extracting <em>positional parameters</em> (packed in a
* JSON array).
* <li>The {@link com.thetransactioncompany.jsonrpc2.util.NamedParamsRetriever}
* class is for extracting <em>named parameters</em> (packed in a JSON
* object).
* </ul>
*
*
* <p><b>Package dependencies:</b> The classes in this package depend on the
* sister {@link com.thetransactioncompany.jsonrpc2} package.
*
* @author Vladimir Dzhuvinov
*/
package com.thetransactioncompany.jsonrpc2.util;

View File

@@ -0,0 +1,129 @@
package net.i2p.i2pcontrol;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import org.apache.http.conn.util.InetAddressUtils;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
/**
* Block certain Host headers to prevent DNS rebinding attacks.
*
* This Handler wraps the ContextHandlerCollection, which handles
* all the webapps (not just routerconsole).
* Therefore, this protects all the webapps.
*
* This class is NOT used for the webapp or the bare ServerSocket implementation.
*
* @since 0.12 copied from routerconsole
*/
public class HostCheckHandler extends HandlerWrapper
{
private final I2PAppContext _context;
private final Set<String> _listenHosts;
/**
* MUST call setListenHosts() afterwards.
*/
public HostCheckHandler(I2PAppContext ctx) {
super();
_context = ctx;
_listenHosts = new HashSet<String>(8);
}
/**
* Set the legal hosts.
* Not synched. Call this BEFORE starting.
* If empty, all are allowed.
*
* @param hosts contains hostnames or IPs. But we allow all IPs anyway.
*/
public void setListenHosts(Set<String> hosts) {
_listenHosts.clear();
_listenHosts.addAll(hosts);
}
/**
* Block by Host header, pass everything else to the delegate.
*/
public void handle(String pathInContext,
Request baseRequest,
HttpServletRequest httpRequest,
HttpServletResponse httpResponse)
throws IOException, ServletException
{
String host = httpRequest.getHeader("Host");
if (!allowHost(host)) {
Log log = _context.logManager().getLog(HostCheckHandler.class);
host = DataHelper.stripHTML(getHost(host));
String s = "Console request denied.\n" +
" To allow access using the hostname \"" + host + "\", add the line \"" +
I2PControlController.PROP_ALLOWED_HOSTS + '=' + host +
"\" to I2PControl.conf and restart.";
log.logAlways(Log.WARN, s);
httpResponse.sendError(403, s);
return;
}
super.handle(pathInContext, baseRequest, httpRequest, httpResponse);
}
/**
* Should we allow a request with this Host header?
*
* ref: https://en.wikipedia.org/wiki/DNS_rebinding
*
* @param host the HTTP Host header, null ok
* @return true if OK
*/
private boolean allowHost(String host) {
if (host == null)
return true;
// common cases
if (host.equals("127.0.0.1:7650") ||
host.equals("localhost:7650"))
return true;
// all allowed?
if (_listenHosts.isEmpty())
return true;
host = getHost(host);
if (_listenHosts.contains(host))
return true;
// allow all IP addresses
if (InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host))
return true;
//System.out.println(host + " not found in " + s);
return false;
}
/**
* Strip [] and port from a host header
*
* @param host the HTTP Host header non-null
*/
private static String getHost(String host) {
if (host.startsWith("[")) {
host = host.substring(1);
int brack = host.indexOf(']');
if (brack >= 0)
host = host.substring(0, brack);
} else {
int colon = host.indexOf(':');
if (colon >= 0)
host = host.substring(0, colon);
}
return host;
}
}

View File

@@ -0,0 +1,406 @@
package net.i2p.i2pcontrol;
/*
* Copyright 2010 hottuna (dev@robertfoss.se)
*
* 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 net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
import net.i2p.util.PortMapper;
import net.i2p.i2pcontrol.security.KeyStoreProvider;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.JSONRPC2Servlet;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
/**
* This handles the starting and stopping of Jetty
* from a single static class so it can be called via clients.config.
*
* This makes installation of a new eepsite a turnkey operation.
*
* Usage: I2PControlController -d $PLUGIN [start|stop]
*
* This class is NOT used for the webapp or the bare ServerSocket implementation.
*
* @author hottuna
*/
public class I2PControlController implements RouterApp {
// non-null
private final I2PAppContext _appContext;
// warning, null in app context
private final RouterContext _context;
private final ClientAppManager _mgr;
private final Log _log;
private final String _pluginDir;
private final ConfigurationManager _conf;
private final KeyStoreProvider _ksp;
private final SecurityManager _secMan;
private final Server _server;
private ClientAppState _state = UNINITIALIZED;
// only for main()
private static I2PControlController _instance;
static final String PROP_ALLOWED_HOSTS = "i2pcontrol.allowedhosts";
private static final String SVC_HTTPS_I2PCONTROL = "https_i2pcontrol";
private static final int DEFAULT_PORT = 7650;
/**
* RouterApp (new way)
*/
public I2PControlController(RouterContext ctx, ClientAppManager mgr, String args[]) {
_appContext = _context = ctx;
_mgr = mgr;
_log = _appContext.logManager().getLog(I2PControlController.class);
File pluginDir = new File(_context.getAppDir(), "plugins/I2PControl");
_pluginDir = pluginDir.getAbsolutePath();
_conf = new ConfigurationManager(_appContext, pluginDir, true);
_ksp = new KeyStoreProvider(_pluginDir);
_secMan = new SecurityManager(_appContext, _ksp, _conf);
_server = buildServer();
_state = INITIALIZED;
}
/**
* From main() (old way)
*/
public I2PControlController(File pluginDir) {
_appContext = I2PAppContext.getGlobalContext();
if (_appContext instanceof RouterContext)
_context = (RouterContext) _appContext;
else
_context = null;
_mgr = null;
_log = _appContext.logManager().getLog(I2PControlController.class);
_pluginDir = pluginDir.getAbsolutePath();
_conf = new ConfigurationManager(_appContext, pluginDir, true);
_ksp = new KeyStoreProvider(_pluginDir);
_secMan = new SecurityManager(_appContext, _ksp, _conf);
_server = buildServer();
_state = INITIALIZED;
}
/////// ClientApp methods
public synchronized void startup() {
changeState(STARTING);
try {
start(null);
changeState(RUNNING);
} catch (Exception e) {
changeState(START_FAILED, "Failed to start", e);
_log.error("Unable to start jetty server", e);
stop();
}
}
public synchronized void shutdown(String[] args) {
if (_state == STOPPED)
return;
changeState(STOPPING);
stop();
changeState(STOPPED);
}
public synchronized ClientAppState getState() {
return _state;
}
public String getName() {
return "I2PControl";
}
public String getDisplayName() {
return "I2PControl";
}
/////// end ClientApp methods
private void changeState(ClientAppState state) {
changeState(state, null, null);
}
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
_state = state;
if (_mgr != null)
_mgr.notify(this, state, msg, e);
if (_context == null) {
if (msg != null)
System.out.println(state + ": " + msg);
if (e != null)
e.printStackTrace();
}
}
/**
* Deprecated, use constructor
*/
public static void main(String args[]) {
if (args.length != 3 || (!"-d".equals(args[0])))
throw new IllegalArgumentException("Usage: PluginController -d $PLUGINDIR [start|stop]");
if ("start".equals(args[2])) {
File pluginDir = new File(args[1]);
if (!pluginDir.exists())
throw new IllegalArgumentException("Plugin directory " + pluginDir.getAbsolutePath() + " does not exist");
synchronized(I2PControlController.class) {
if (_instance != null)
throw new IllegalStateException();
I2PControlController i2pcc = new I2PControlController(pluginDir);
try {
i2pcc.startup();
_instance = i2pcc;
} catch (Exception e) {
e.printStackTrace();
}
}
} else if ("stop".equals(args[2])) {
synchronized(I2PControlController.class) {
if (_instance != null) {
_instance.shutdown(null);
_instance = null;
}
}
} else {
throw new IllegalArgumentException("Usage: PluginController -d $PLUGINDIR [start|stop]");
}
}
private synchronized void start(String args[]) throws Exception {
_appContext.logManager().getLog(JSONRPC2Servlet.class).setMinimumPriority(Log.DEBUG);
_server.start();
_context.portMapper().register(SVC_HTTPS_I2PCONTROL,
_conf.getConf("i2pcontrol.listen.address", "127.0.0.1"),
_conf.getConf("i2pcontrol.listen.port", DEFAULT_PORT));
}
/**
* Builds a new server. Used for changing ports during operation and such.
* @return Server - A new server built from current configuration.
*/
private Connector buildDefaultListener(Server server) {
Connector ssl = buildSslListener(server, _conf.getConf("i2pcontrol.listen.address", "127.0.0.1"),
_conf.getConf("i2pcontrol.listen.port", DEFAULT_PORT));
return ssl;
}
/**
* Builds a new server. Used for changing ports during operation and such.
*
* Does NOT start the server. Must call start() on the returned server.
*
* @return Server - A new server built from current configuration.
*/
public Server buildServer() {
Server server = new Server();
Connector ssl = buildDefaultListener(server);
server.addConnector(ssl);
ServletHandler sh = new ServletHandler();
sh.addServletWithMapping(new ServletHolder(new JSONRPC2Servlet(_context, _secMan)), "/");
HostCheckHandler hch = new HostCheckHandler(_appContext);
Set<String> listenHosts = new HashSet<String>(8);
// fix up the allowed hosts set (see HostCheckHandler)
// empty set says all are valid
String address = _conf.getConf("i2pcontrol.listen.address", "127.0.0.1");
if (!(address.equals("0.0.0.0") ||
address.equals("::") ||
address.equals("0:0:0:0:0:0:0:0"))) {
listenHosts.add("localhost");
listenHosts.add("127.0.0.1");
listenHosts.add("::1");
listenHosts.add("0:0:0:0:0:0:0:1");
String allowed = _conf.getConf(PROP_ALLOWED_HOSTS, "");
if (!allowed.equals("")) {
StringTokenizer tok = new StringTokenizer(allowed, " ,");
while (tok.hasMoreTokens()) {
listenHosts.add(tok.nextToken());
}
}
}
hch.setListenHosts(listenHosts);
hch.setHandler(sh);
server.getServer().setHandler(hch);
_conf.writeConfFile();
return server;
}
/**
* Creates a SSLListener with all the default options. The listener will use all the default options.
* @param address - The address the listener will listen to.
* @param port - The port the listener will listen to.
* @return - Newly created listener
*/
private Connector buildSslListener(Server server, String address, int port) {
int listeners = 0;
if (server != null) {
listeners = server.getConnectors().length;
}
// the keystore path and password
SslContextFactory sslFactory = new SslContextFactory(_ksp.getKeyStoreLocation());
sslFactory.setKeyStorePassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
// the X.509 cert password (if not present, verifyKeyStore() returned false)
sslFactory.setKeyManagerPassword(KeyStoreProvider.DEFAULT_CERTIFICATE_PASSWORD);
sslFactory.addExcludeProtocols(I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.size()]));
sslFactory.addExcludeCipherSuites(I2PSSLSocketFactory.EXCLUDE_CIPHERS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_CIPHERS.size()]));
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
httpConfig.setSecurePort(port);
httpConfig.addCustomizer(new SecureRequestCustomizer());
// number of acceptors, (default) number of selectors
ServerConnector ssl = new ServerConnector(server, 1, 0,
new SslConnectionFactory(sslFactory, "http/1.1"),
new HttpConnectionFactory(httpConfig));
ssl.setHost(address);
ssl.setPort(port);
ssl.setIdleTimeout(90*1000); // default 10 sec
// all with same name will use the same thread pool
ssl.setName("I2PControl");
ssl.setName("SSL Listener-" + ++listeners);
return ssl;
}
/**
* Add a listener to the server
* If a listener listening to the same port as the provided listener
* uses already exists within the server, replace the one already used by
* the server with the provided listener.
* @param listener
* @throws Exception
*/
/****
public synchronized void replaceListener(Connector listener) throws Exception {
if (_server != null) {
stopServer();
}
_server = buildServer(listener);
}
****/
/**
* Get all listeners of the server.
* @return
*/
/****
public synchronized Connector[] getListeners() {
if (_server != null) {
return _server.getConnectors();
}
return new Connector[0];
}
****/
/**
* Removes all listeners
*/
/****
public synchronized void clearListeners() {
if (_server != null) {
for (Connector listen : getListeners()) {
_server.removeConnector(listen);
}
}
}
****/
/**
* Stop it
*/
private synchronized void stopServer()
{
try {
if (_server != null) {
_appContext.portMapper().unregister(SVC_HTTPS_I2PCONTROL);
_server.stop();
for (Connector listener : _server.getConnectors()) {
listener.stop();
}
_server.destroy();
}
} catch (Exception e) {
_log.error("Stopping server", e);
}
}
private synchronized void stop() {
_conf.writeConfFile();
_secMan.stopTimedEvents();
stopServer();
/****
// Get and stop all running threads
ThreadGroup threadgroup = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[threadgroup.activeCount() + 3];
threadgroup.enumerate(threads, true);
for (Thread thread : threads) {
if (thread != null) {//&& thread.isAlive()){
thread.interrupt();
}
}
for (Thread thread : threads) {
if (thread != null) {
System.out.println("Active thread: " + thread.getName());
}
}
threadgroup.interrupt();
//Thread.currentThread().getThreadGroup().destroy();
****/
}
public String getPluginDir() {
return _pluginDir;
}
}

View File

@@ -0,0 +1,20 @@
package net.i2p.i2pcontrol;
import java.util.HashSet;
import java.util.Set;
public class I2PControlVersion {
/** The current version of I2PControl */
public final static String VERSION = "0.12.0";
/** The current version of the I2PControl API being primarily being implemented */
public final static int API_VERSION = 1;
/** The supported versions of the I2PControl API */
public final static Set<Integer> SUPPORTED_API_VERSIONS;
static {
SUPPORTED_API_VERSIONS = new HashSet<Integer>();
SUPPORTED_API_VERSIONS.add(1);
}
}

View File

@@ -0,0 +1,246 @@
package net.i2p.i2pcontrol;
/*
* Copyright 2010 hottuna (dev@robertfoss.se)
*
* 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.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
import net.i2p.util.PortMapper;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import net.i2p.i2pcontrol.security.KeyStoreProvider;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.JSONRPC2Servlet;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
/**
* This handles the starting and stopping of a ServerSocket
* from a single static class so it can be called via clients.config.
*
* This class is NOT used for the webapp or the HTTP/HTTPS implementation.
*
* @author hottuna
*/
public class SocketController implements RouterApp {
// non-null
private final RouterContext _context;
private final ClientAppManager _mgr;
private final Log _log;
private final String _pluginDir;
private final ConfigurationManager _conf;
private final KeyStoreProvider _ksp;
private final SecurityManager _secMan;
private ServerSocket _server;
private final List<Socket> _listeners;
private ClientAppState _state = UNINITIALIZED;
// only for main()
private static SocketController _instance;
static final String PROP_ALLOWED_HOSTS = "i2pcontrol.allowedhosts";
private static final String SVC_SKT_I2PCONTROL = "skt_i2pcontrol";
private static final String SVC_SSL_I2PCONTROL = "skt_ssl_i2pcontrol";
private static final int DEFAULT_PORT = 7640;
/**
* RouterApp (new way)
*/
public SocketController(RouterContext ctx, ClientAppManager mgr, String args[]) throws IOException {
_context = ctx;
_mgr = mgr;
_log = _context.logManager().getLog(SocketController.class);
File pluginDir = new File(_context.getConfigDir(), "keystore/I2PControl");
_pluginDir = pluginDir.getAbsolutePath();
_conf = new ConfigurationManager(_context, pluginDir, true);
_ksp = new KeyStoreProvider(_pluginDir);
_secMan = new SecurityManager(_context, _ksp, _conf);
_listeners = new ArrayList<Socket>(4);
_state = INITIALIZED;
}
/////// ClientApp methods
public synchronized void startup() {
changeState(STARTING);
try {
start(null);
changeState(RUNNING);
} catch (Exception e) {
changeState(START_FAILED, "Failed to start", e);
_log.error("Unable to start socket server", e);
stop();
}
}
public synchronized void shutdown(String[] args) {
if (_state == STOPPED)
return;
changeState(STOPPING);
stop();
changeState(STOPPED);
}
public synchronized ClientAppState getState() {
return _state;
}
public String getName() {
return "I2PControl-Socket";
}
public String getDisplayName() {
return "I2PControl-Socket";
}
/////// end ClientApp methods
private void changeState(ClientAppState state) {
changeState(state, null, null);
}
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
_state = state;
if (_mgr != null)
_mgr.notify(this, state, msg, e);
if (_context == null) {
if (msg != null)
System.out.println(state + ": " + msg);
if (e != null)
e.printStackTrace();
}
}
private synchronized void start(String args[]) throws Exception {
_context.logManager().getLog(JSONRPC2Servlet.class).setMinimumPriority(Log.DEBUG);
_server = buildServer();
_context.portMapper().register(SVC_SKT_I2PCONTROL,
_conf.getConf("i2pcontrol.listen.address", "127.0.0.1"),
_conf.getConf("i2pcontrol.listen.port", DEFAULT_PORT));
}
/**
* Builds a new server. Used for changing ports during operation and such.
*
* Does NOT start the server. Must call start() on the returned server.
*
* @return Server - A new server built from current configuration.
*/
public ServerSocket buildServer() throws IOException {
String address = _conf.getConf("i2pcontrol.listen.address", "127.0.0.1");
int port = _conf.getConf("i2pcontrol.listen.port", DEFAULT_PORT);
ServerSocket server = new ServerSocket(port, 0, InetAddress.getByName(address));
_conf.writeConfFile();
return server;
}
private class Server implements Runnable {
public void run() {
try {
while (true) {
Socket s = _server.accept();
synchronized (SocketController.this) {
_listeners.add(s);
}
new Handler(s);
}
} catch (IOException ioe) {
_log.error("i2pcontrol server", ioe);
} finally {
synchronized (SocketController.this) {
if (_server != null) {
try { _server.close(); } catch (IOException ioe) {}
}
}
}
}
}
private class Handler implements Runnable {
private final Socket s;
public Handler(Socket skt) { s = skt; }
public void run() {
try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
final JSONParser parser = new JSONParser();
while (true) {
Object o = parser.parse(reader);
// TODO
System.out.println("i2pcontrol got: " + o);
}
} catch (ParseException pe) {
_log.error("i2pcontrol handler", pe);
return;
} catch (IOException ioe) {
_log.error("i2pcontrol handler", ioe);
return;
} finally {
synchronized (SocketController.this) {
_listeners.remove(s);
}
try { s.close(); } catch (IOException ioe) {}
}
}
}
/**
* Stop it
*/
private synchronized void stopServer()
{
try {
if (_server != null) {
_context.portMapper().unregister(SVC_SKT_I2PCONTROL);
try {
_server.close();
} catch (IOException ioe) {}
for (Socket listener : _listeners) {
try {
listener.close();
} catch (IOException ioe) {}
}
_listeners.clear();
}
} catch (Exception e) {
_log.error("Stopping server", e);
}
}
private synchronized void stop() {
_conf.writeConfFile();
_secMan.stopTimedEvents();
stopServer();
}
}

View File

@@ -0,0 +1,50 @@
package net.i2p.i2pcontrol.security;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class AuthToken {
static final int VALIDITY_TIME = 1; // Measured in days
private final SecurityManager _secMan;
private final String id;
private final Date expiry;
public AuthToken(SecurityManager secMan, String password) {
_secMan = secMan;
String hash = _secMan.getPasswdHash(password);
this.id = _secMan.getHash(hash + Calendar.getInstance().getTimeInMillis());
Calendar expiry = Calendar.getInstance();
expiry.add(Calendar.DAY_OF_YEAR, VALIDITY_TIME);
this.expiry = expiry.getTime();
}
public String getId() {
return id;
}
/**
* Checks whether the AuthToken has expired.
* @return True if AuthToken hasn't expired. False in any other case.
*/
public boolean isValid() {
return Calendar.getInstance().getTime().before(expiry);
}
public String getExpiryTime() {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
return sdf.format(expiry);
}
@Override
public String toString() {
return id;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@@ -0,0 +1,16 @@
package net.i2p.i2pcontrol.security;
public class ExpiredAuthTokenException extends Exception {
private static final long serialVersionUID = 2279019346592900289L;
private String expiryTime;
public ExpiredAuthTokenException(String str, String expiryTime) {
super(str);
this.expiryTime = expiryTime;
}
public String getExpirytime() {
return expiryTime;
}
}

View File

@@ -0,0 +1,9 @@
package net.i2p.i2pcontrol.security;
public class InvalidAuthTokenException extends Exception {
private static final long serialVersionUID = 7605321329341235577L;
public InvalidAuthTokenException(String str) {
super(str);
}
}

View File

@@ -0,0 +1,218 @@
package net.i2p.i2pcontrol.security;
import net.i2p.crypto.KeyStoreUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class KeyStoreProvider {
public static final String DEFAULT_CERTIFICATE_ALGORITHM_STRING = "RSA";
public static final int DEFAULT_CERTIFICATE_KEY_LENGTH = 4096;
public static final int DEFAULT_CERTIFICATE_VALIDITY = 365 * 10;
public final static String DEFAULT_CERTIFICATE_DOMAIN = "localhost";
public final static String DEFAULT_CERTIFICATE_ALIAS = "I2PControl CA";
public static final String DEFAULT_KEYSTORE_NAME = "i2pcontrol.ks";
public static final String DEFAULT_KEYSTORE_PASSWORD = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
public static final String DEFAULT_CERTIFICATE_PASSWORD = "nut'nfancy";
private final String _pluginDir;
private KeyStore _keystore;
public KeyStoreProvider(String pluginDir) {
_pluginDir = pluginDir;
}
public void initialize() {
KeyStoreUtil.createKeys(new File(getKeyStoreLocation()),
DEFAULT_KEYSTORE_PASSWORD,
DEFAULT_CERTIFICATE_ALIAS,
DEFAULT_CERTIFICATE_DOMAIN,
"i2pcontrol",
DEFAULT_CERTIFICATE_VALIDITY,
DEFAULT_CERTIFICATE_ALGORITHM_STRING,
DEFAULT_CERTIFICATE_KEY_LENGTH,
DEFAULT_CERTIFICATE_PASSWORD);
}
/**
* @param password unused
* @return null on failure
*/
public static X509Certificate readCert(KeyStore ks, String certAlias, String password) {
try {
X509Certificate cert = (X509Certificate) ks.getCertificate(certAlias);
if (cert == null) {
throw new RuntimeException("Got null cert from keystore!");
}
try {
cert.verify(cert.getPublicKey());
return cert;
} catch (Exception e) {
System.err.println("Failed to verify caCert certificate against caCert");
e.printStackTrace();
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
return null;
}
/**
* @param password for the keystore
* @return null on failure
*/
/****
public static X509Certificate readCert(File keyStoreFile, String certAlias, String password) {
try {
KeyStore ks = getDefaultKeyStore();
ks.load(new FileInputStream(keyStoreFile), password.toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(certAlias);
if (cert == null) {
throw new RuntimeException("Got null cert from keystore!");
}
try {
cert.verify(cert.getPublicKey());
return cert;
} catch (Exception e) {
System.err.println("Failed to verify caCert certificate against caCert");
e.printStackTrace();
}
} catch (IOException e) {
System.err.println("Couldn't read keystore from: " + keyStoreFile.toString());
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
System.err.println("No certificate with alias: " + certAlias + " found.");
e.printStackTrace();
}
return null;
}
****/
/**
* @param password for the key
* @return null on failure, or throws RuntimeException...
*/
/****
public static PrivateKey readPrivateKey(KeyStore ks, String alias, String password) {
try {
// load the key entry from the keystore
Key key = ks.getKey(alias, password.toCharArray());
if (key == null) {
throw new RuntimeException("Got null key from keystore!");
}
PrivateKey privKey = (PrivateKey) key;
return privKey;
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return null;
}
****/
/**
* @return null on failure
*/
/****
public static PrivateKey readPrivateKey(String alias, File keyStoreFile, String keyStorePassword, String keyPassword) {
try {
KeyStore ks = getDefaultKeyStore();
ks.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
return readPrivateKey(ks, alias, keyStorePassword);
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.err.println("Couldn't read keystore from: " + keyStoreFile.toString());
e.printStackTrace();
}
return null;
}
****/
/**
* @return null on failure
*/
/****
public static KeyStore writeCACertToKeyStore(KeyStore keyStore, String keyPassword, String alias, PrivateKey caPrivKey, X509Certificate caCert) {
try {
X509Certificate[] chain = new X509Certificate[1];
chain[0] = caCert;
keyStore.setKeyEntry(alias, caPrivKey, keyPassword.toCharArray(), chain);
File keyStoreFile = new File(I2PControlController.getPluginDir() + File.separator + DEFAULT_KEYSTORE_NAME);
keyStore.store(new FileOutputStream(keyStoreFile), DEFAULT_KEYSTORE_PASSWORD.toCharArray());
return keyStore;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
****/
/**
* @return null on failure
*/
public synchronized KeyStore getDefaultKeyStore() {
if (_keystore == null) {
File keyStoreFile = new File(getKeyStoreLocation());
try {
_keystore = KeyStore.getInstance(KeyStore.getDefaultType());
if (keyStoreFile.exists()) {
InputStream is = new FileInputStream(keyStoreFile);
_keystore.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
return _keystore;
}
initialize();
if (keyStoreFile.exists()) {
InputStream is = new FileInputStream(keyStoreFile);
_keystore.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
return _keystore;
} else {
throw new IOException("KeyStore file " + keyStoreFile.getAbsolutePath() + " wasn't readable");
}
} catch (Exception e) {
// Ignore. Not an issue. Let's just create a new keystore instead.
}
return null;
} else {
return _keystore;
}
}
public String getKeyStoreLocation() {
File keyStoreFile = new File(_pluginDir, DEFAULT_KEYSTORE_NAME);
return keyStoreFile.getAbsolutePath();
}
}

View File

@@ -0,0 +1,252 @@
package net.i2p.i2pcontrol.security;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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 net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256Generator;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import org.mindrot.jbcrypt.BCrypt;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.security.KeyStore;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
/**
* Manage the password storing for I2PControl.
*/
public class SecurityManager {
public final static String DEFAULT_AUTH_PASSWORD = "itoopie";
private final HashMap<String, AuthToken> authTokens;
private final SimpleTimer2.TimedEvent timer;
private final KeyStore _ks;
private final Log _log;
private final ConfigurationManager _conf;
private final I2PAppContext _context;
/**
* @param ksp may be null (if webapp)
*/
public SecurityManager(I2PAppContext ctx, KeyStoreProvider ksp, ConfigurationManager conf) {
_context = ctx;
_conf = conf;
_log = ctx.logManager().getLog(SecurityManager.class);
authTokens = new HashMap<String, AuthToken>();
timer = new Sweeper();
_ks = ksp != null ? ksp.getDefaultKeyStore() : null;
}
public void stopTimedEvents() {
timer.cancel();
synchronized (authTokens) {
authTokens.clear();
}
}
/**
* Return the X509Certificate of the server as a Base64 encoded string.
* @return base64 encode of X509Certificate
*/
/**** unused and incorrectly uses I2P Base64. Switch to CertUtil.exportCert() if needed.
public String getBase64Cert() {
X509Certificate caCert = KeyStoreProvider.readCert(_ks,
KeyStoreProvider.DEFAULT_CERTIFICATE_ALIAS,
KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD);
return getBase64FromCert(caCert);
}
****/
/**
* Return the X509Certificate as a base64 encoded string.
* @param cert
* @return base64 encode of X509Certificate
*/
/**** unused and incorrectly uses I2P Base64. Switch to CertUtil.exportCert() if needed.
private static String getBase64FromCert(X509Certificate cert) {
try {
return Base64.encode(cert.getEncoded());
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
return null;
}
****/
/**
* Hash pwd with using BCrypt with the default salt.
* @param pwd
* @return BCrypt hash of salt and input string
*/
public String getPasswdHash(String pwd) {
String salt;
synchronized(_conf) {
salt = _conf.getConf("auth.salt", "");
if (salt.equals("")) {
salt = BCrypt.gensalt(10, _context.random());
_conf.setConf("auth.salt", salt);
_conf.writeConfFile();
}
}
return BCrypt.hashpw(pwd, salt);
}
/**
* Get saved password hash. Stores if not previously set.
* @return BCrypt hash of salt and password
* @since 0.12
*/
private String getSavedPasswdHash() {
String pw;
synchronized(_conf) {
pw = _conf.getConf("auth.password", "");
if (pw.equals("")) {
pw = getPasswdHash(DEFAULT_AUTH_PASSWORD);
_conf.setConf("auth.password", pw);
_conf.writeConfFile();
}
}
return pw;
}
/**
* Hash input one time with SHA-256, return Base64 encdoded string.
* @param string
* @return Base64 encoded string
*/
public String getHash(String string) {
SHA256Generator hashGen = _context.sha();
byte[] bytes = string.getBytes();
bytes = hashGen.calculateHash(bytes).toByteArray();
return Base64.encode(bytes);
}
/**
* Is this password correct?
* @return true if password is valid.
* @since 0.12
*/
public boolean isValid(String pwd) {
String storedPass = getSavedPasswdHash();
byte[] p1 = DataHelper.getASCII(getPasswdHash(pwd));
byte[] p2 = DataHelper.getASCII(storedPass);
return p1.length == p2.length && DataHelper.eqCT(p1, 0, p2, 0, p1.length);
}
/**
* Is this password correct?
* @return true if password is valid.
* @since 0.12
*/
public boolean isDefaultPasswordValid() {
return isValid(DEFAULT_AUTH_PASSWORD);
}
/**
* Add a Authentication Token if the provided password is valid.
* The token will be valid for one day.
* @return AuthToken if password is valid. If password is invalid null will be returned.
*/
public AuthToken validatePasswd(String pwd) {
if (isValid(pwd)) {
AuthToken token = new AuthToken(this, pwd);
synchronized (authTokens) {
authTokens.put(token.getId(), token);
}
return token;
} else {
return null;
}
}
/**
* Set new password. Old tokens will NOT remain valid, to encourage the new password being tested.
* @param newPasswd
* @return Returns true if a new password was set.
*/
public boolean setPasswd(String newPasswd) {
String newHash = getPasswdHash(newPasswd);
String oldHash = getSavedPasswdHash();
if (!newHash.equals(oldHash)) {
_conf.setConf("auth.password", newHash);
_conf.writeConfFile();
synchronized (authTokens) {
authTokens.clear();
}
return true;
}
return false;
}
/**
* Checks whether the AuthToken with the given ID exists and if it does whether is has expired.
* @param tokenID - The token to validate
* @throws InvalidAuthTokenException
* @throws ExpiredAuthTokenException
*/
public void verifyToken(String tokenID) throws InvalidAuthTokenException, ExpiredAuthTokenException {
synchronized (authTokens) {
AuthToken token = authTokens.get(tokenID);
if (token == null)
throw new InvalidAuthTokenException("AuthToken with ID: " + tokenID + " couldn't be found.");
if (!token.isValid()) {
authTokens.remove(tokenID);
throw new ExpiredAuthTokenException("AuthToken with ID: " + tokenID + " expired " + token.getExpiryTime(), token.getExpiryTime());
}
}
// Everything is fine. :)
}
/**
* Clean up old authorization tokens to keep the token store slim and fit.
* @author hottuna
*
*/
private class Sweeper extends SimpleTimer2.TimedEvent {
// Start running periodic task after 1 day, run periodically every 30 minutes.
public Sweeper() {
super(_context.simpleTimer2(), AuthToken.VALIDITY_TIME * 24*60*60*1000L);
}
public void timeReached() {
_log.debug("Starting cleanup job..");
synchronized (authTokens) {
for (Iterator<AuthToken> iter = authTokens.values().iterator(); iter.hasNext(); ) {
AuthToken token = iter.next();
if (!token.isValid())
iter.remove();
}
}
_log.debug("Cleanup job done.");
schedule(30*60*1000L);
}
}
}

View File

@@ -0,0 +1,245 @@
package net.i2p.i2pcontrol.servlets;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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 com.thetransactioncompany.jsonrpc2.*;
import com.thetransactioncompany.jsonrpc2.server.Dispatcher;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.util.PortMapper;
import net.i2p.i2pcontrol.I2PControlVersion;
import net.i2p.i2pcontrol.security.KeyStoreProvider;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.jsonrpc2handlers.*;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
/**
* Provide an JSON-RPC 2.0 API for remote controlling of I2P
*/
public class JSONRPC2Servlet extends HttpServlet {
private static final long serialVersionUID = -45075606818515212L;
private static final int BUFFER_LENGTH = 2048;
private static final String SVC_HTTP_I2PCONTROL = "http_i2pcontrol";
private static final String SVC_HTTPS_I2PCONTROL = "https_i2pcontrol";
private Dispatcher disp;
private Log _log;
private final SecurityManager _secMan;
private final ConfigurationManager _conf;
private final JSONRPC2Helper _helper;
private final RouterContext _context;
private final boolean _isWebapp;
private boolean _isHTTP, _isHTTPS;
/**
* Webapp
*/
public JSONRPC2Servlet() {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (!ctx.isRouterContext())
throw new IllegalStateException();
_context = (RouterContext) ctx;
File appDir = ctx.getAppDir();
_conf = new ConfigurationManager(ctx, appDir, false);
// we don't really need a keystore
//File ksDir = new File(ctx.getConfigDir(), "keystore");
//ksDir.mkDir();
//KeyStoreProvider ksp = new KeyStoreProvider(ksDir.getAbsolutePath());
//_secMan = new SecurityManager(ctx, ksp, _conf);
_secMan = new SecurityManager(ctx, null, _conf);
_helper = new JSONRPC2Helper(_secMan);
_log = ctx.logManager().getLog(JSONRPC2Servlet.class);
_conf.writeConfFile();
_isWebapp = true;
}
/**
* Plugin
*/
public JSONRPC2Servlet(RouterContext ctx, SecurityManager secMan) {
_context = ctx;
_secMan = secMan;
_helper = new JSONRPC2Helper(_secMan);
if (ctx != null)
_log = ctx.logManager().getLog(JSONRPC2Servlet.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(JSONRPC2Servlet.class);
_conf = null;
_isWebapp = false;
}
@Override
public void init() throws ServletException {
super.init();
disp = new Dispatcher();
disp.register(new EchoHandler(_helper));
disp.register(new GetRateHandler(_helper));
disp.register(new AuthenticateHandler(_helper, _secMan));
disp.register(new NetworkSettingHandler(_context, _helper));
disp.register(new RouterInfoHandler(_context, _helper));
disp.register(new RouterManagerHandler(_context, _helper));
disp.register(new I2PControlHandler(_context, _helper, _secMan));
disp.register(new AdvancedSettingsHandler(_context, _helper));
if (_isWebapp) {
PortMapper pm = _context.portMapper();
int port = pm.getPort(PortMapper.SVC_CONSOLE);
if (port > 0) {
String host = pm.getHost(PortMapper.SVC_CONSOLE, "127.0.0.1");
pm.register(SVC_HTTP_I2PCONTROL, host, port);
_isHTTP = true;
}
port = pm.getPort(PortMapper.SVC_HTTPS_CONSOLE);
if (port > 0) {
String host = pm.getHost(PortMapper.SVC_HTTPS_CONSOLE, "127.0.0.1");
pm.register(SVC_HTTPS_I2PCONTROL, host, port);
_isHTTPS = true;
}
}
}
@Override
public void destroy() {
if (_isWebapp) {
PortMapper pm = _context.portMapper();
if (_isHTTP)
pm.unregister(SVC_HTTP_I2PCONTROL);
if (_isHTTPS)
pm.unregister(SVC_HTTPS_I2PCONTROL);
_secMan.stopTimedEvents();
_conf.writeConfFile();
}
super.destroy();
}
@Override
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
httpServletResponse.setContentType("text/html");
PrintWriter out = httpServletResponse.getWriter();
out.println("<p>I2PControl RPC Service version " + I2PControlVersion.VERSION + " : Running");
if ("/password".equals(httpServletRequest.getServletPath())) {
out.println("<form method=\"POST\" action=\"password\">");
if (_secMan.isDefaultPasswordValid()) {
out.println("<p>The current API password is the default, \"" + _secMan.DEFAULT_AUTH_PASSWORD + "\". You should change it.");
} else {
out.println("<p>Current API password:<input name=\"password\" type=\"password\">");
}
out.println("<p>New API password (twice):<input name=\"password2\" type=\"password\">" +
"<input name=\"password3\" type=\"password\">" +
"<input name=\"save\" type=\"submit\" value=\"Change API Password\">" +
"<p>If you forget the API password, stop i2pcontrol, delete the file <tt>" + _conf.getConfFile() +
"</tt>, and restart i2pcontrol.");
} else {
out.println("<p><a href=\"password\">Change API Password</a>");
}
out.close();
}
/** @since 0.12 */
private void doPasswordChange(HttpServletRequest req, HttpServletResponse httpServletResponse) throws ServletException, IOException {
httpServletResponse.setContentType("text/html");
PrintWriter out = httpServletResponse.getWriter();
String pw = req.getParameter("password");
if (pw == null)
pw = _secMan.DEFAULT_AUTH_PASSWORD;
else
pw = pw.trim();
String pw2 = req.getParameter("password2");
String pw3 = req.getParameter("password3");
if (pw2 == null || pw3 == null) {
out.println("<p>Enter new password twice!");
} else {
pw2 = pw2.trim();
pw3 = pw3.trim();
if (!pw2.equals(pw3)) {
out.println("<p>New passwords don't match!");
} else if (pw2.length() <= 0) {
out.println("<p>Enter new password twice!");
} else if (_secMan.isValid(pw)) {
_secMan.setPasswd(pw2);
out.println("<p>API Password changed");
} else {
out.println("<p>Incorrect old password, not changed");
}
}
out.println("<p><a href=\"password\">Change API Password</a>");
}
@Override
protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
if ("/password".equals(httpServletRequest.getServletPath())) {
doPasswordChange(httpServletRequest, httpServletResponse);
return;
}
String req = getRequest(httpServletRequest.getInputStream());
httpServletResponse.setContentType("application/json");
PrintWriter out = httpServletResponse.getWriter();
JSONRPC2Message msg = null;
JSONRPC2Response jsonResp = null;
try {
msg = JSONRPC2Message.parse(req);
if (msg instanceof JSONRPC2Request) {
jsonResp = disp.process((JSONRPC2Request)msg, null);
jsonResp.toJSONObject().put("API", I2PControlVersion.API_VERSION);
if (_log.shouldDebug()) {
_log.debug("Request: " + msg);
_log.debug("Response: " + jsonResp);
}
}
else if (msg instanceof JSONRPC2Notification) {
disp.process((JSONRPC2Notification)msg, null);
if (_log.shouldDebug())
_log.debug("Notification: " + msg);
}
out.println(jsonResp);
out.close();
} catch (JSONRPC2ParseException e) {
_log.error("Unable to parse JSONRPC2Message: " + e.getMessage());
}
}
private String getRequest(ServletInputStream sis) throws IOException {
Writer writer = new StringWriter();
BufferedReader reader = new BufferedReader(new InputStreamReader(sis, "UTF-8"));
char[] readBuffer = new char[BUFFER_LENGTH];
int n;
while ((n = reader.read(readBuffer)) != -1) {
writer.write(readBuffer, 0, n);
}
return writer.toString();
}
}

View File

@@ -0,0 +1,219 @@
package net.i2p.i2pcontrol.servlets.configuration;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
/**
* Manage the configuration of I2PControl.
* @author mathias
* modified: hottuna
*
*/
public class ConfigurationManager {
private final String CONFIG_FILE = "I2PControl.conf";
private final String WEBAPP_CONFIG_FILE = "i2pcontrol.config";
private final File configLocation;
private final Log _log;
private boolean _changed;
//Configurations with a String as value
private final Map<String, String> stringConfigurations = new HashMap<String, String>();
//Configurations with a Boolean as value
private final Map<String, Boolean> booleanConfigurations = new HashMap<String, Boolean>();
//Configurations with an Integer as value
private final Map<String, Integer> integerConfigurations = new HashMap<String, Integer>();
public ConfigurationManager(I2PAppContext ctx, File dir, boolean isPlugin) {
_log = ctx.logManager().getLog(ConfigurationManager.class);
if (isPlugin) {
configLocation = new File(dir, CONFIG_FILE);
} else {
configLocation = new File(dir, WEBAPP_CONFIG_FILE);
}
readConfFile();
}
/** @since 0.12 */
public File getConfFile() {
return configLocation;
}
/**
* Collects arguments of the form --word, --word=otherword and -blah
* to determine user parameters.
* @param settingNames Command line arguments to the application
*/
/****
public void loadArguments(String[] settingNames) {
for (int i = 0; i < settingNames.length; i++) {
String settingName = settingNames[i];
if (settingName.startsWith("--")) {
parseConfigStr(settingName.substring(2));
}
}
}
****/
/**
* Reads configuration from file, every line is parsed as key=value.
*/
public synchronized void readConfFile() {
try {
Properties input = new Properties();
// true: map to lower case
DataHelper.loadProps(input, configLocation, true);
parseConfigStr(input);
_changed = false;
} catch (FileNotFoundException e) {
if (_log.shouldInfo())
_log.info("Unable to find config file, " + configLocation);
} catch (IOException e) {
_log.error("Unable to read from config file, " + configLocation, e);
}
}
/**
* Write configuration into default config file.
* As of 0.12, doesn't actually write unless something changed.
*/
public synchronized void writeConfFile() {
if (!_changed)
return;
Properties tree = new OrderedProperties();
tree.putAll(stringConfigurations);
for (Entry<String, Integer> e : integerConfigurations.entrySet()) {
tree.put(e.getKey(), e.getValue().toString());
}
for (Entry<String, Boolean> e : booleanConfigurations.entrySet()) {
tree.put(e.getKey(), e.getValue().toString());
}
try {
DataHelper.storeProps(tree, configLocation);
_changed = false;
} catch (IOException e1) {
_log.error("Couldn't open file, " + configLocation + " for writing config.");
}
}
/**
* Try to parse the input as 'key=value',
* where value will (in order) be parsed as integer/boolean/string.
* @param str
*/
private void parseConfigStr(Properties input) {
for (Entry<Object, Object> entry : input.entrySet()) {
String key = (String) entry.getKey();
String value = (String) entry.getValue();
//Try parse as integer.
try {
int i = Integer.parseInt(value);
integerConfigurations.put(key, i);
continue;
} catch (NumberFormatException e) {}
//Check if value is a bool
if (value.toLowerCase().equals("true")) {
booleanConfigurations.put(key, Boolean.TRUE);
continue;
} else if (value.toLowerCase().equals("false")) {
booleanConfigurations.put(key, Boolean.FALSE);
continue;
}
stringConfigurations.put(key, value);
}
}
/**
* Check if a specific boolean configuration exists.
* @param settingName The key for the configuration.
* @param defaultValue If the configuration is not found, we use a default value.
* @return The value of a configuration: true if found, defaultValue if not found.
*/
public synchronized boolean getConf(String settingName, boolean defaultValue) {
Boolean value = booleanConfigurations.get(settingName);
if (value != null) {
return value;
} else {
booleanConfigurations.put(settingName, defaultValue);
_changed = true;
return defaultValue;
}
}
/**
* Check if a specific boolean configuration exists.
* @param settingName The key for the configuration.
* @param defaultValue If the configuration is not found, we use a default value.
* @return The value of a configuration: true if found, defaultValue if not found.
*/
public synchronized int getConf(String settingName, int defaultValue) {
Integer value = integerConfigurations.get(settingName);
if (value != null) {
return value;
} else {
integerConfigurations.put(settingName, defaultValue);
_changed = true;
return defaultValue;
}
}
/**
* Get a specific String configuration.
* @param settingName The key for the configuration.
* @param defaultValue If the configuration is not found, we use a default value.
* @return The value of the configuration, or the defaultValue.
*/
public synchronized String getConf(String settingName, String defaultValue) {
String value = stringConfigurations.get(settingName);
if (value != null) {
return value;
} else {
stringConfigurations.put(settingName, defaultValue);
_changed = true;
return defaultValue;
}
}
/**
* Set a specific int setting
* @param settingName
* @param nbr
*/
public synchronized void setConf(String settingName, int nbr) {
integerConfigurations.put(settingName, nbr);
_changed = true;
}
/**
* Set a specific string setting
* @param settingName
* @param str
*/
public synchronized void setConf(String settingName, String str) {
stringConfigurations.put(settingName, str);
_changed = true;
}
/**
* Set a specific boolean setting
* @param settingName
* @param bool
*/
public synchronized void setConf(String settingName, boolean bool) {
booleanConfigurations.put(settingName, bool);
_changed = true;
}
}

View File

@@ -0,0 +1,200 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class AdvancedSettingsHandler implements RequestHandler {
private final RouterContext _context;
private final Log _log;
private final JSONRPC2Helper _helper;
private static final String[] requiredArgs = {};
public AdvancedSettingsHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
if (ctx != null)
_log = ctx.logManager().getLog(AdvancedSettingsHandler.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(AdvancedSettingsHandler.class);
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"AdvancedSettings"};
}
// Processes the requests
@SuppressWarnings("unchecked")
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("AdvancedSettings")) {
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null) {
return new JSONRPC2Response(err, req.getID());
}
if (_context == null) {
return new JSONRPC2Response(new JSONRPC2Error(
JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
@SuppressWarnings("rawtypes")
Map<String, Object> inParams = req.getNamedParams();
Map outParams = new HashMap();
if (inParams.containsKey("setAll")) {
Object obj = inParams.get("setAll");
if (!(obj instanceof Map)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Value of \"setAll\" is not a Map");
return new JSONRPC2Response(rpcErr, req.getID());
}
@SuppressWarnings("rawtypes")
Map objMap = (Map) inParams.get("setAll");
if (objMap.size() > 0)
{
if (!(objMap.keySet().toArray()[0] instanceof String) &&
!(objMap.values().toArray()[0] instanceof String)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Map of settings does not contain String keys and values");
return new JSONRPC2Response(rpcErr, req.getID());
}
if (!checkTypes(objMap)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"Some of the supplied values are not strings");
return new JSONRPC2Response(rpcErr, req.getID());
}
Map<String, String> allSettings = (Map<String, String>) objMap;
boolean success = setAdvancedSettings(allSettings, true);
if (!success) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"Failed to save new config");
return new JSONRPC2Response(rpcErr, req.getID());
}
} else {
// Empty list of settings submitted
boolean success = setAdvancedSettings(null, true);
if (!success) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"Failed to save new config");
return new JSONRPC2Response(rpcErr, req.getID());
}
}
}
if (inParams.containsKey("getAll")) {
outParams.put("getAll", getAdvancedSettings());
}
if (inParams.containsKey("set")) {
Object obj = inParams.get("set");
if (!(obj instanceof Map)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Value of \"set\" is not a Map");
return new JSONRPC2Response(rpcErr, req.getID());
}
Map objMap = (Map) inParams.get("set");
if (objMap.size() > 0)
{
if (!(objMap.keySet().toArray()[0] instanceof String) &&
!(objMap.values().toArray()[0] instanceof String)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Map of settings does not contain String keys and values");
return new JSONRPC2Response(rpcErr, req.getID());
}
if (!checkTypes(objMap)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"Some of the supplied values are not strings");
return new JSONRPC2Response(rpcErr, req.getID());
}
Map<String, String> allSettings = (Map<String, String>) objMap;
boolean success = setAdvancedSettings(allSettings, false);
if (!success) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"Failed to save new config");
return new JSONRPC2Response(rpcErr, req.getID());
}
} else {
// Empty list of settings submitted
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Map of settings does not contain any entries");
return new JSONRPC2Response(rpcErr, req.getID());
}
}
if (inParams.containsKey("get")) {
Object obj = inParams.get("get");
if (!(obj instanceof String)) {
JSONRPC2Error rpcErr = new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"Value of \"get\" is not a string");
return new JSONRPC2Response(rpcErr, req.getID());
}
String getStr = (String) obj;
String getVal = getAdvancedSetting(getStr);
Map<String, String> outMap = new HashMap<String, String>();
outMap.put(getStr, getVal);
outParams.put("get", outMap);
}
return new JSONRPC2Response(outParams, req.getID());
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
private String getAdvancedSetting(String key) {
return _context.router().getConfigSetting(key);
}
private Map<String, String> getAdvancedSettings() {
return _context.router().getConfigMap();
}
private boolean checkTypes(Map<String, Object> newSettings) {
for (String key : newSettings.keySet()) {
if (!(newSettings.get(key) instanceof String)) {
return false;
}
}
return true;
}
private boolean setAdvancedSettings(Map<String, String> newSettings, boolean clearConfig) {
Set<String> unsetKeys = null;
if (clearConfig) {
unsetKeys = new HashSet<String>(_context.router().getConfigSettings());
for (String key : newSettings.keySet()) {
unsetKeys.remove(key);
}
}
return _context.router().saveConfig(newSettings, unsetKeys);
}
}

View File

@@ -0,0 +1,105 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.i2pcontrol.I2PControlVersion;
import net.i2p.i2pcontrol.security.AuthToken;
import net.i2p.i2pcontrol.security.SecurityManager;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class AuthenticateHandler implements RequestHandler {
private static final String[] requiredArgs = {"Password", "API"};
private final JSONRPC2Helper _helper;
private final SecurityManager _secMan;
public AuthenticateHandler(JSONRPC2Helper helper, SecurityManager secMan) {
_helper = helper;
_secMan = secMan;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"Authenticate"};
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("Authenticate")) {
JSONRPC2Error err = _helper.validateParams(requiredArgs, req, JSONRPC2Helper.USE_NO_AUTH);
if (err != null)
return new JSONRPC2Response(err, req.getID());
Map<String, Object> inParams = req.getNamedParams();
String pwd = (String) inParams.get("Password");
// Try get an AuthToken
AuthToken token = _secMan.validatePasswd(pwd);
if (token == null) {
return new JSONRPC2Response(JSONRPC2ExtendedError.INVALID_PASSWORD, req.getID());
}
Object api = inParams.get("API");
err = validateAPIVersion(api);
if (err != null)
return new JSONRPC2Response(err, req.getID());
Map<String, Object> outParams = new HashMap<String, Object>(4);
outParams.put("Token", token.getId());
outParams.put("API", I2PControlVersion.API_VERSION);
return new JSONRPC2Response(outParams, req.getID());
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
/**
* Validate the provided I2PControl API version against the ones supported by I2PControl.
*/
private static JSONRPC2Error validateAPIVersion(Object api) {
Integer apiVersion;
try {
apiVersion = ((Long) api).intValue();
} catch (ClassCastException e) {
e.printStackTrace();
return JSONRPC2ExtendedError.UNSPECIFIED_API_VERSION;
}
if (!I2PControlVersion.SUPPORTED_API_VERSIONS.contains(apiVersion)) {
String supportedAPIVersions = "";
for (Integer i : I2PControlVersion.SUPPORTED_API_VERSIONS) {
supportedAPIVersions += ", " + i;
}
return new JSONRPC2Error(JSONRPC2ExtendedError.UNSUPPORTED_API_VERSION.getCode(),
"The provided API version \'" + apiVersion + "\' is not supported. The supported versions are" + supportedAPIVersions + ".");
}
return null;
}
}

View File

@@ -0,0 +1,44 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import java.util.HashMap;
import java.util.Map;
public class EchoHandler implements RequestHandler {
private static final String[] requiredArgs = {"Echo"};
private final JSONRPC2Helper _helper;
public EchoHandler(JSONRPC2Helper helper) {
_helper = helper;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"Echo"};
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("Echo")) {
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
Map<String, Object> inParams = req.getNamedParams();
String echo = (String) inParams.get("Echo");
Map<String, Object> outParams = new HashMap<String, Object>(4);
outParams.put("Result", echo);
return new JSONRPC2Response(outParams, req.getID());
}
else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
}

View File

@@ -0,0 +1,85 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class GetRateHandler implements RequestHandler {
private static final String[] requiredArgs = {"Stat", "Period"};
private final JSONRPC2Helper _helper;
public GetRateHandler(JSONRPC2Helper helper) {
_helper = helper;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"GetRate"};
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("GetRate")) {
JSONRPC2Error err = _helper.validateParams(requiredArgs, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
Map<String, Object> inParams = req.getNamedParams();
String input = (String) inParams.get("Stat");
if (input == null) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
}
long period;
try {
period = (Long) inParams.get("Period");
} catch (NumberFormatException e) {
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
}
RateStat rateStat = I2PAppContext.getGlobalContext().statManager().getRate(input);
// If RateStat or the requested period doesn't already exist, create them.
if (rateStat == null || rateStat.getRate(period) == null) {
long[] tempArr = new long[1];
tempArr[0] = period;
I2PAppContext.getGlobalContext().statManager().createRequiredRateStat(input, "I2PControl", "I2PControl", tempArr);
rateStat = I2PAppContext.getGlobalContext().statManager().getRate(input);
}
if (rateStat.getRate(period) == null)
return new JSONRPC2Response(JSONRPC2Error.INTERNAL_ERROR, req.getID());
Map<String, Object> outParams = new HashMap<String, Object>(4);
Rate rate = rateStat.getRate(period);
rate.coalesce();
outParams.put("Result", rate.getAverageValue());
return new JSONRPC2Response(outParams, req.getID());
}
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}

View File

@@ -0,0 +1,205 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.i2pcontrol.I2PControlController;
import net.i2p.i2pcontrol.security.SecurityManager;
import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class I2PControlHandler implements RequestHandler {
private static final int BW_BURST_PCT = 110;
private static final int BW_BURST_TIME = 20;
private final RouterContext _context;
private final Log _log;
//private final ConfigurationManager _conf;
private final SecurityManager _secMan;
private final JSONRPC2Helper _helper;
public I2PControlHandler(RouterContext ctx, JSONRPC2Helper helper, SecurityManager secMan) {
_helper = helper;
_secMan = secMan;
_context = ctx;
if (ctx != null)
_log = ctx.logManager().getLog(I2PControlHandler.class);
else
_log = I2PAppContext.getGlobalContext().logManager().getLog(I2PControlHandler.class);
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"I2PControl"};
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("I2PControl")) {
return process(req);
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
/**** only if we enable host/port changes
if (_context == null) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
****/
Map<String, Object> inParams = req.getNamedParams();
Map<String, Object> outParams = new HashMap<String, Object>(4);
boolean restartNeeded = false;
boolean settingsSaved = false;
String inParam;
/****
if (inParams.containsKey("i2pcontrol.port")) {
Integer oldPort = _conf.getConf("i2pcontrol.listen.port", 7650);
if ((inParam = (String) inParams.get("i2pcontrol.port")) != null) {
if (oldPort == null || !inParam.equals(oldPort.toString())) {
Integer newPort;
try {
newPort = Integer.valueOf(inParam);
if (newPort < 1 || newPort > 65535) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2pcontrol.port\" must be a string representing a number in the range 1-65535. " + inParam + " isn't valid."),
req.getID());
}
try {
SslSocketConnector ssl = I2PControlController.buildSslListener(_conf.getConf("i2pcontrol.listen.address", "127.0.0.1"), newPort);
I2PControlController.clearListeners();
I2PControlController.replaceListener(ssl);
_conf.setConf("i2pcontrol.listen.port", newPort);
ConfigurationManager.writeConfFile();
outParams.put("i2pcontrol.port", null);
settingsSaved = true;
} catch (Exception e) {
try {
_conf.setConf("i2pcontrol.listen.port", oldPort);
SslSocketConnector ssl = I2PControlController.buildSslListener(_conf.getConf("i2pcontrol.listen.address", "127.0.0.1"), oldPort);
I2PControlController.clearListeners();
I2PControlController.replaceListener(ssl);
} catch (Exception e2) {
_log.log(Log.CRIT, "Unable to resume server on previous listening port.");
}
_log.error("Client tried to set listen port to, " + newPort + " which isn't valid.", e);
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2pcontrol.port\" has been set to a port that is already in use, reverting. " +
inParam + " is an already used port.\n"
+ "Exception: " + e.toString()),
req.getID());
}
}
}
outParams.put("RestartNeeded", restartNeeded);
}
****/
if (inParams.containsKey("i2pcontrol.password")) {
if ((inParam = (String) inParams.get("i2pcontrol.password")) != null) {
if (_secMan.setPasswd(inParam)) {
outParams.put("i2pcontrol.password", null);
settingsSaved = true;
}
}
}
/****
if (inParams.containsKey("i2pcontrol.address")) {
String oldAddress = _conf.getConf("i2pcontrol.listen.address", "127.0.0.1");
if ((inParam = (String) inParams.get("i2pcontrol.address")) != null) {
if ((oldAddress == null || !inParam.equals(oldAddress.toString()) &&
(inParam.equals("0.0.0.0") || inParam.equals("127.0.0.1")))) {
InetAddress[] newAddress;
try {
newAddress = InetAddress.getAllByName(inParam);
} catch (UnknownHostException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2pcontrol.address\" must be a string representing a hostname or ipaddress. " + inParam + " isn't valid."),
req.getID());
}
try {
SslSocketConnector ssl = I2PControlController.buildSslListener(inParam, _conf.getConf("i2pcontrol.listen.port", 7650));
I2PControlController.clearListeners();
I2PControlController.replaceListener(ssl);
_conf.setConf("i2pcontrol.listen.address", inParam);
ConfigurationManager.writeConfFile();
outParams.put("i2pcontrol.address", null);
settingsSaved = true;
} catch (Exception e) {
_conf.setConf("i2pcontrol.listen.address", oldAddress);
try {
SslSocketConnector ssl = I2PControlController.buildSslListener(inParam, _conf.getConf("i2pcontrol.listen.port", 7650));
I2PControlController.clearListeners();
I2PControlController.replaceListener(ssl);
} catch (Exception e2) {
_log.log(Log.CRIT, "Unable to resume server on previous listening ip.");
}
_log.error("Client tried to set listen address to, " + newAddress.toString() + " which isn't valid.", e);
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2pcontrol.address\" has been set to an invalid address, reverting. "), req.getID());
}
}
} else {
outParams.put("i2pcontrol.address", oldAddress);
}
outParams.put("RestartNeeded", restartNeeded);
}
****/
outParams.put("SettingsSaved", settingsSaved);
return new JSONRPC2Response(outParams, req.getID());
}
}

View File

@@ -0,0 +1,124 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import org.json.simple.JSONObject;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
/**
* Represents a JSON-RPC 2.0 error that occured during the processing of a
* request.
*
* <p>The protocol expects error objects to be structured like this:
*
* <ul>
* <li>{@code code} An integer that indicates the error type.
* <li>{@code message} A string providing a short description of the
* error. The message should be limited to a concise single sentence.
* <li>{@code data} Additional information, which may be omitted. Its
* contents is entirely defined by the application.
* </ul>
*
* <p>Note that the "Error" word in the class name was put there solely to
* comply with the parlance of the JSON-RPC spec. This class doesn't inherit
* from {@code java.lang.Error}. It's a regular subclass of
* {@code java.lang.Exception} and, if thrown, it's to indicate a condition
* that a reasonable application might want to catch.
*
* <p>This class also includes convenient final static instances for all
* standard JSON-RPC 2.0 errors:
*
* <ul>
* <li>{@link #PARSE_ERROR} JSON parse error (-32700)
* <li>{@link #INVALID_REQUEST} Invalid JSON-RPC 2.0 Request (-32600)
* <li>{@link #METHOD_NOT_FOUND} Method not found (-32601)
* <li>{@link #INVALID_PARAMS} Invalid parameters (-32602)
* <li>{@link #INTERNAL_ERROR} Internal error (-32603)
* </ul>
*
* <p>Note that the range -32099..-32000 is reserved for additional server
* errors.
*
* <p id="map">The mapping between JSON and Java entities (as defined by the
* underlying JSON.simple library):
* <pre>
* true|false &lt;---&gt; java.lang.Boolean
* number &lt;---&gt; java.lang.Number
* string &lt;---&gt; java.lang.String
* array &lt;---&gt; java.util.List
* object &lt;---&gt; java.util.Map
* null &lt;---&gt; null
* </pre>
*
* <p>The JSON-RPC 2.0 specification and user group forum can be found
* <a href="http://groups.google.com/group/json-rpc">here</a>.
*
* @author <a href="http://dzhuvinov.com">Vladimir Dzhuvinov</a>
* @version 1.16 (2010-10-04)
*/
public class JSONRPC2ExtendedError extends JSONRPC2Error {
private static final long serialVersionUID = -6574632977222371077L;
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error INVALID_PASSWORD = new JSONRPC2ExtendedError(-32001, "Invalid password provided.");
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error NO_TOKEN = new JSONRPC2ExtendedError(-32002, "No authentication token presented.");
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error INVALID_TOKEN = new JSONRPC2ExtendedError(-32003, "Authentication token doesn't exist.");
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error TOKEN_EXPIRED = new JSONRPC2ExtendedError(-32004, "Provided authentication token was expired and will be removed.");
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error UNSPECIFIED_API_VERSION = new JSONRPC2ExtendedError(-32005, "The version of the I2PControl API wasn't specified, but is required to be specified.");
/** Invalid JSON-RPC 2.0, implementation defined error (-32099 .. -32000) */
public static final JSONRPC2Error UNSUPPORTED_API_VERSION = new JSONRPC2ExtendedError(-32006, "The version of the I2PControl API specified is not supported by I2PControl.");
/**
* Creates a new JSON-RPC 2.0 error with the specified code and
* message. The optional data is omitted.
*
* @param code The error code (standard pre-defined or
* application-specific).
* @param message The error message.
*/
public JSONRPC2ExtendedError(int code, String message) {
super(code, message);
}
/**
* Creates a new JSON-RPC 2.0 error with the specified code,
* message and data.
*
* @param code The error code (standard pre-defined or
* application-specific).
* @param message The error message.
* @param data Optional error data, must <a href="#map">map</a>
* to a valid JSON type.
*/
public JSONRPC2ExtendedError(int code, String message, Object data) {
super(code, message, data);
}
}

View File

@@ -0,0 +1,111 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2ParamsType;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import net.i2p.i2pcontrol.security.ExpiredAuthTokenException;
import net.i2p.i2pcontrol.security.InvalidAuthTokenException;
import net.i2p.i2pcontrol.security.SecurityManager;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class JSONRPC2Helper {
public final static Boolean USE_NO_AUTH = false;
public final static Boolean USE_AUTH = true;
private final SecurityManager _secMan;
public JSONRPC2Helper(SecurityManager secMan) {
_secMan = secMan;
}
/**
* Check incoming request for required arguments, to make sure they are valid.
* @param requiredArgs - Array of names of required arguments. If null don't check for any parameters.
* @param req - Incoming JSONRPC2 request
* @param useAuth - If true, will validate authentication token.
* @return - null if no errors were found. Corresponding JSONRPC2Error if error is found.
*/
public JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req, Boolean useAuth) {
// Error on unnamed parameters
if (req.getParamsType() != JSONRPC2ParamsType.OBJECT) {
return JSONRPC2Error.INVALID_PARAMS;
}
Map<String, Object> params = req.getNamedParams();
// Validate authentication token.
if (useAuth) {
JSONRPC2Error err = validateToken(params);
if (err != null) {
return err;
}
}
// If there exist any required arguments.
if (requiredArgs != null && requiredArgs.length > 0) {
String missingArgs = "";
for (int i = 0; i < requiredArgs.length; i++) {
if (!params.containsKey(requiredArgs[i])) {
missingArgs = missingArgs.concat(requiredArgs[i] + ",");
}
}
if (missingArgs.length() > 0) {
missingArgs = missingArgs.substring(0, missingArgs.length() - 1);
return new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(), "Missing parameter(s): " + missingArgs);
}
}
return null;
}
/**
* Check incoming request for required arguments, to make sure they are valid. Will authenticate req.
* @param requiredArgs - Array of names of required arguments. If null don't check for any parameters.
* @param req - Incoming JSONRPC2 request
* @return - null if no errors were found. Corresponding JSONRPC2Error if error is found.
*/
public JSONRPC2Error validateParams(String[] requiredArgs, JSONRPC2Request req) {
return validateParams(requiredArgs, req, JSONRPC2Helper.USE_AUTH);
}
/**
* Will check incoming parameters to make sure they contain a valid token.
* @param req - Parameters of incoming request
* @return null if everything is fine, JSONRPC2Error for any corresponding error.
*/
private JSONRPC2Error validateToken(Map<String, Object> params) {
String tokenID = (String) params.get("Token");
if (tokenID == null) {
return JSONRPC2ExtendedError.NO_TOKEN;
}
try {
_secMan.verifyToken(tokenID);
} catch (InvalidAuthTokenException e) {
return JSONRPC2ExtendedError.INVALID_TOKEN;
} catch (ExpiredAuthTokenException e) {
JSONRPC2Error err = new JSONRPC2ExtendedError(JSONRPC2ExtendedError.TOKEN_EXPIRED.getCode(),
"Provided authentication token expired " + e.getExpirytime() + ", will be removed.");
return err;
}
return null;
}
}

View File

@@ -0,0 +1,344 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.transport.FIFOBandwidthRefiller;
import net.i2p.router.transport.TransportManager;
import net.i2p.router.transport.ntcp.NTCPTransport;
import net.i2p.router.transport.udp.UDPTransport;
import net.i2p.util.Log;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class NetworkSettingHandler implements RequestHandler {
private static final int BW_BURST_PCT = 110;
private static final int BW_BURST_TIME = 20;
private final JSONRPC2Helper _helper;
private final RouterContext _context;
public NetworkSettingHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] {"NetworkSetting"};
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("NetworkSetting")) {
return process(req);
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID());
}
}
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
if (_context == null) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
Map<String, Object> inParams = req.getNamedParams();
Map<String, Object> outParams = new HashMap<String, Object>(4);
boolean restartNeeded = false;
boolean settingsSaved = false;
String inParam;
if (inParams.containsKey("i2p.router.net.ntcp.port")) {
String oldNTCPPort = _context.getProperty(NTCPTransport.PROP_I2NP_NTCP_PORT);
if ((inParam = (String) inParams.get("i2p.router.net.ntcp.port")) != null) {
if (oldNTCPPort == null || !oldNTCPPort.equals(inParam.trim())) {
Integer newPort;
try {
newPort = Integer.valueOf(inParam);
if (newPort < 1 || newPort > 65535) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.ntcp.port\" must be a string representing a number in the range 1-65535. " + inParam + " isn't valid."),
req.getID());
}
Map<String, String> config = new HashMap<String, String>();
config.put(NTCPTransport.PROP_I2NP_NTCP_PORT, String.valueOf(newPort));
config.put(NTCPTransport.PROP_I2NP_NTCP_AUTO_PORT, "false");
_context.router().saveConfig(config, null);
restartNeeded = true;
}
settingsSaved = true;
} else {
String sAutoPort = _context.getProperty(NTCPTransport.PROP_I2NP_NTCP_AUTO_PORT, "true");
boolean oldAutoPort = "true".equalsIgnoreCase(sAutoPort);
if (oldAutoPort) {
String oldSSUPort = "" + _context.getProperty(UDPTransport.PROP_INTERNAL_PORT, 8887);
outParams.put("i2p.router.net.ntcp.port", oldSSUPort);
} else {
outParams.put("i2p.router.net.ntcp.port", oldNTCPPort);
}
}
}
if (inParams.containsKey("i2p.router.net.ntcp.hostname")) {
String oldNTCPHostname = _context.getProperty(NTCPTransport.PROP_I2NP_NTCP_HOSTNAME);
if ((inParam = (String) inParams.get("i2p.router.net.ntcp.hostname")) != null) {
if (oldNTCPHostname == null || !oldNTCPHostname.equals(inParam.trim())) {
_context.router().saveConfig(NTCPTransport.PROP_I2NP_NTCP_HOSTNAME, inParam);
restartNeeded = true;
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.ntcp.hostname", oldNTCPHostname);
}
}
if (inParams.containsKey("i2p.router.net.ntcp.autoip")) {
String oldNTCPAutoIP = _context.getProperty(NTCPTransport.PROP_I2NP_NTCP_AUTO_IP);
if ((inParam = (String) inParams.get("i2p.router.net.ntcp.autoip")) != null) {
inParam = inParam.trim().toLowerCase();
if (oldNTCPAutoIP == null || !oldNTCPAutoIP.equals(inParam)) {
if ("always".equals(inParam) || "true".equals(inParam) || "false".equals(inParam)) {
_context.router().saveConfig(NTCPTransport.PROP_I2NP_NTCP_AUTO_IP, inParam);
restartNeeded = true;
} else {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.ntcp.autoip\" can only be always, true or false. " + inParam + " isn't valid."),
req.getID());
}
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.ntcp.autoip", oldNTCPAutoIP);
}
}
if (inParams.containsKey("i2p.router.net.ssu.port")) {
String oldSSUPort = "" + _context.getProperty(UDPTransport.PROP_INTERNAL_PORT, 8887);
if ((inParam = (String) inParams.get("i2p.router.net.ssu.port")) != null) {
if (oldSSUPort == null || !oldSSUPort.equals(inParam.trim())) {
Integer newPort;
try {
newPort = Integer.valueOf(inParam);
if (newPort < 1 || newPort > 65535) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.ssu.port\" must be a string representing a number in the range 1-65535. " + inParam + " isn't valid."),
req.getID());
}
Map<String, String> config = new HashMap<String, String>();
config.put(UDPTransport.PROP_EXTERNAL_PORT, String.valueOf(newPort));
config.put(UDPTransport.PROP_INTERNAL_PORT, String.valueOf(newPort));
_context.router().saveConfig(config, null);
restartNeeded = true;
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.ssu.port", oldSSUPort);
}
}
if (inParams.containsKey("i2p.router.net.ssu.hostname")) {
String oldSSUHostname = _context.getProperty(UDPTransport.PROP_EXTERNAL_HOST);
if ((inParam = (String) inParams.get("i2p.router.net.ssu.hostname")) != null) {
if (oldSSUHostname == null || !oldSSUHostname.equals(inParam.trim())) {
_context.router().saveConfig(UDPTransport.PROP_EXTERNAL_HOST, inParam);
restartNeeded = true;
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.ssu.hostname", oldSSUHostname);
}
}
if (inParams.containsKey("i2p.router.net.ssu.autoip")) {
String oldSSUAutoIP = _context.getProperty(UDPTransport.PROP_SOURCES);
if ((inParam = (String) inParams.get("i2p.router.net.ssu.autoip")) != null) {
inParam = inParam.trim().toLowerCase();
if (oldSSUAutoIP == null || !oldSSUAutoIP.equals(inParam)) {
if (inParam.equals("ssu") || inParam.equals("local,ssu") || inParam.equals("upnp,ssu") || inParam.equals("local,upnp,ssu")) {
_context.router().saveConfig(UDPTransport.PROP_SOURCES, inParam);
restartNeeded = true;
} else {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.ssu.autoip\" can only be ssu/local,upnp,ssu/local/ssu/upnp,ssu. " + inParam + " isn't valid."),
req.getID());
}
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.ssu.autoip", oldSSUAutoIP);
}
}
// Non-setable key.
if (inParams.containsKey("i2p.router.net.ssu.detectedip")) {
if ((inParam = (String) inParams.get("i2p.router.net.ssu.autoip")) == null) {
byte[] ipBytes = _context.router().getRouterInfo().getTargetAddress("SSU").getIP();
try {
InetAddress i = InetAddress.getByAddress(ipBytes);
outParams.put("i2p.router.net.ssu.detectedip", i.getHostAddress());
} catch (UnknownHostException e) {
outParams.put("i2p.router.net.ssu.detectedip", "Failed to parse ip address");
}
}
}
if (inParams.containsKey("i2p.router.net.upnp")) {
String oldUPNP = _context.getProperty(TransportManager.PROP_ENABLE_UPNP);
if ((inParam = (String) inParams.get("i2p.router.net.upnp")) != null) {
if (oldUPNP == null || !oldUPNP.equals(inParam.trim())) {
_context.router().saveConfig(TransportManager.PROP_ENABLE_UPNP, inParam);
restartNeeded = true;
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.upnp", oldUPNP);
}
}
if (inParams.containsKey("i2p.router.net.bw.share")) {
String oldShare = _context.router().getConfigSetting(Router.PROP_BANDWIDTH_SHARE_PERCENTAGE);
if ((inParam = (String) inParams.get("i2p.router.net.bw.share")) != null) {
if (oldShare == null || !oldShare.equals(inParam.trim())) {
Integer percent;
try {
percent = Integer.parseInt(inParam);
if (percent < 0 || percent > 100 || inParam.length() == 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.bw.share\" A positive integer must supplied, \"" + inParam + "\" isn't valid"),
req.getID());
}
_context.router().saveConfig(Router.PROP_BANDWIDTH_SHARE_PERCENTAGE, inParam);
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.bw.share", oldShare);
}
}
if (inParams.containsKey("i2p.router.net.bw.in")) {
String oldBWIn = _context.getProperty(FIFOBandwidthRefiller.PROP_INBOUND_BANDWIDTH);
if ((inParam = (String) inParams.get("i2p.router.net.bw.in")) != null) {
Integer rate;
try {
rate = Integer.parseInt(inParam);
if (rate < 0 || inParam.length() == 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.bw.in\" A positive integer must supplied, " + inParam + " isn't valid"),
req.getID());
}
Integer burstRate = (rate * BW_BURST_PCT) / 100;
Integer burstSize = (burstRate * BW_BURST_TIME);
if (oldBWIn == null || !oldBWIn.equals(rate.toString())) {
Map<String, String> config = new HashMap<String, String>();
config.put(FIFOBandwidthRefiller.PROP_INBOUND_BANDWIDTH, rate.toString());
config.put(FIFOBandwidthRefiller.PROP_INBOUND_BURST_BANDWIDTH, burstRate.toString());
config.put(FIFOBandwidthRefiller.PROP_INBOUND_BANDWIDTH_PEAK, burstSize.toString());
_context.router().saveConfig(config, null);
_context.bandwidthLimiter().reinitialize();
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.bw.in", oldBWIn);
}
}
if (inParams.containsKey("i2p.router.net.bw.out")) {
String oldBWOut = _context.getProperty(FIFOBandwidthRefiller.PROP_OUTBOUND_BANDWIDTH);
if ((inParam = (String) inParams.get("i2p.router.net.bw.out")) != null) {
Integer rate;
try {
rate = Integer.parseInt(inParam);
if (rate < 0 || inParam.length() == 0)
throw new NumberFormatException();
} catch (NumberFormatException e) {
return new JSONRPC2Response(
new JSONRPC2Error(JSONRPC2Error.INVALID_PARAMS.getCode(),
"\"i2p.router.net.bw.out\" A positive integer must supplied, " + inParam + " isn't valid"),
req.getID());
}
Integer burstRate = (rate * BW_BURST_PCT) / 100;
Integer burstSize = (burstRate * BW_BURST_TIME);
if (oldBWOut == null || !oldBWOut.equals(rate.toString())) {
Map<String, String> config = new HashMap<String, String>();
config.put(FIFOBandwidthRefiller.PROP_OUTBOUND_BANDWIDTH, rate.toString());
config.put(FIFOBandwidthRefiller.PROP_OUTBOUND_BURST_BANDWIDTH, burstRate.toString());
config.put(FIFOBandwidthRefiller.PROP_OUTBOUND_BANDWIDTH_PEAK, burstSize.toString());
_context.router().saveConfig(config, null);
_context.bandwidthLimiter().reinitialize();
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.bw.out", oldBWOut);
}
}
if (inParams.containsKey("i2p.router.net.laptopmode")) {
String oldLaptopMode = _context.getProperty(UDPTransport.PROP_LAPTOP_MODE);
if ((inParam = (String) inParams.get("i2p.router.net.laptopmode")) != null) {
if (oldLaptopMode == null || !oldLaptopMode.equals(inParam.trim())) {
_context.router().saveConfig(UDPTransport.PROP_LAPTOP_MODE, String.valueOf(inParam));
}
settingsSaved = true;
} else {
outParams.put("i2p.router.net.laptopmode", oldLaptopMode);
}
}
if (settingsSaved)
_context.router().saveConfig();
outParams.put("SettingsSaved", settingsSaved);
outParams.put("RestartNeeded", restartNeeded);
return new JSONRPC2Response(outParams, req.getID());
}
}

View File

@@ -0,0 +1,213 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.data.router.RouterAddress;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.transport.TransportUtil;
import net.i2p.router.transport.ntcp.NTCPTransport;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class RouterInfoHandler implements RequestHandler {
private final JSONRPC2Helper _helper;
private final RouterContext _context;
public RouterInfoHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] { "RouterInfo" };
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("RouterInfo")) {
return process(req);
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND,
req.getID());
}
}
@SuppressWarnings("unchecked")
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
if (_context == null) {
return new JSONRPC2Response(new JSONRPC2Error(
JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
Map<String, Object> inParams = req.getNamedParams();
Map outParams = new HashMap();
if (inParams.containsKey("i2p.router.version")) {
try {
Class rvClass = Class.forName("net.i2p.router.RouterVersion");
java.lang.reflect.Field field = rvClass.getDeclaredField("FULL_VERSION");
String fullVersion = (String) field.get(new RouterVersion());
outParams.put("i2p.router.version", fullVersion);
} catch (Exception e) {} // Ignore
}
if (inParams.containsKey("i2p.router.uptime")) {
Router router = _context.router();
if (router == null) {
outParams.put("i2p.router.uptime", 0);
} else {
outParams.put("i2p.router.uptime", router.getUptime());
}
}
if (inParams.containsKey("i2p.router.status")) {
outParams.put("i2p.router.status", _context.throttle().getTunnelStatus());
}
if (inParams.containsKey("i2p.router.net.status")) {
outParams.put("i2p.router.net.status", getNetworkStatus().ordinal());
}
if (inParams.containsKey("i2p.router.net.bw.inbound.1s")) {
outParams.put("i2p.router.net.bw.inbound.1s", _context.bandwidthLimiter().getReceiveBps());
}
if (inParams.containsKey("i2p.router.net.bw.outbound.1s")) {
outParams.put("i2p.router.net.bw.outbound.1s", _context.bandwidthLimiter().getSendBps());
}
if (inParams.containsKey("i2p.router.net.bw.inbound.15s")) {
outParams.put("i2p.router.net.bw.inbound.15s", _context.bandwidthLimiter().getReceiveBps15s());
}
if (inParams.containsKey("i2p.router.net.bw.outbound.15s")) {
outParams.put("i2p.router.net.bw.outbound.15s", _context.bandwidthLimiter().getSendBps15s());
}
if (inParams.containsKey("i2p.router.net.tunnels.participating")) {
outParams.put("i2p.router.net.tunnels.participating", _context.tunnelManager().getParticipatingCount());
}
if (inParams.containsKey("i2p.router.netdb.knownpeers")) {
// Why max(-1, 0) is used I don't know, it is the implementation used in the router console.
outParams.put("i2p.router.netdb.knownpeers", Math.max(_context.netDb().getKnownRouters() - 1, 0));
}
if (inParams.containsKey("i2p.router.netdb.activepeers")) {
outParams.put("i2p.router.netdb.activepeers", _context.commSystem().countActivePeers());
}
if (inParams.containsKey("i2p.router.netdb.fastpeers")) {
outParams.put("i2p.router.netdb.fastpeers", _context.profileOrganizer().countFastPeers());
}
if (inParams.containsKey("i2p.router.netdb.highcapacitypeers")) {
outParams.put("i2p.router.netdb.highcapacitypeers", _context.profileOrganizer().countHighCapacityPeers());
}
if (inParams.containsKey("i2p.router.netdb.isreseeding")) {
outParams.put("i2p.router.netdb.isreseeding", Boolean.valueOf(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress")).booleanValue());
}
return new JSONRPC2Response(outParams, req.getID());
}
private static enum NETWORK_STATUS {
OK,
TESTING,
FIREWALLED,
HIDDEN,
WARN_FIREWALLED_AND_FAST,
WARN_FIREWALLED_AND_FLOODFILL,
WARN_FIREWALLED_WITH_INBOUND_TCP,
WARN_FIREWALLED_WITH_UDP_DISABLED,
ERROR_I2CP,
ERROR_CLOCK_SKEW,
ERROR_PRIVATE_TCP_ADDRESS,
ERROR_SYMMETRIC_NAT,
ERROR_UDP_PORT_IN_USE,
ERROR_NO_ACTIVE_PEERS_CHECK_CONNECTION_AND_FIREWALL,
ERROR_UDP_DISABLED_AND_TCP_UNSET,
};
// Ripped out of SummaryHelper.java
private NETWORK_STATUS getNetworkStatus() {
if (_context.router().getUptime() > 60 * 1000
&& (!_context.router().gracefulShutdownInProgress())
&& !_context.clientManager().isAlive())
return (NETWORK_STATUS.ERROR_I2CP);
long skew = _context.commSystem().getFramedAveragePeerClockSkew(33);
// Display the actual skew, not the offset
if (Math.abs(skew) > 60 * 1000)
return NETWORK_STATUS.ERROR_CLOCK_SKEW;
if (_context.router().isHidden())
return (NETWORK_STATUS.HIDDEN);
int status = _context.commSystem().getStatus().getCode();
switch (status) {
case CommSystemFacade.STATUS_OK:
RouterAddress ra = _context.router().getRouterInfo().getTargetAddress("NTCP");
if (ra == null || TransportUtil.isPubliclyRoutable(ra.getIP(), true))
return NETWORK_STATUS.OK;
return NETWORK_STATUS.ERROR_PRIVATE_TCP_ADDRESS;
case CommSystemFacade.STATUS_DIFFERENT:
return NETWORK_STATUS.ERROR_SYMMETRIC_NAT;
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
if (_context.router().getRouterInfo().getTargetAddress("NTCP") != null)
return NETWORK_STATUS.WARN_FIREWALLED_WITH_INBOUND_TCP;
if (((FloodfillNetworkDatabaseFacade) _context.netDb()).floodfillEnabled())
return NETWORK_STATUS.WARN_FIREWALLED_AND_FLOODFILL;
if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
return NETWORK_STATUS.WARN_FIREWALLED_AND_FAST;
return NETWORK_STATUS.FIREWALLED;
case CommSystemFacade.STATUS_HOSED:
return NETWORK_STATUS.ERROR_UDP_PORT_IN_USE;
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
default:
ra = _context.router().getRouterInfo().getTargetAddress("SSU");
if (ra == null && _context.router().getUptime() > 5 * 60 * 1000) {
if (_context.commSystem().countActivePeers() <= 0)
return NETWORK_STATUS.ERROR_NO_ACTIVE_PEERS_CHECK_CONNECTION_AND_FIREWALL;
else if (_context.getProperty(NTCPTransport.PROP_I2NP_NTCP_HOSTNAME) == null || _context.getProperty(NTCPTransport.PROP_I2NP_NTCP_PORT) == null)
return NETWORK_STATUS.ERROR_UDP_DISABLED_AND_TCP_UNSET;
else
return NETWORK_STATUS.WARN_FIREWALLED_WITH_UDP_DISABLED;
}
return NETWORK_STATUS.TESTING;
}
}
}

View File

@@ -0,0 +1,231 @@
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.thetransactioncompany.jsonrpc2.server.MessageContext;
import com.thetransactioncompany.jsonrpc2.server.RequestHandler;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.networkdb.reseed.ReseedChecker;
import net.i2p.update.UpdateManager;
import net.i2p.update.UpdateType;
import net.i2p.util.Log;
import org.tanukisoftware.wrapper.WrapperManager;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2011 hottuna (dev@robertfoss.se)
*
* 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.
*
*/
public class RouterManagerHandler implements RequestHandler {
private final JSONRPC2Helper _helper;
private final RouterContext _context;
private final static int SHUTDOWN_WAIT = 1500;
public RouterManagerHandler(RouterContext ctx, JSONRPC2Helper helper) {
_helper = helper;
_context = ctx;
}
// Reports the method names of the handled requests
public String[] handledRequests() {
return new String[] { "RouterManager" };
}
// Processes the requests
public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) {
if (req.getMethod().equals("RouterManager")) {
return process(req);
} else {
// Method name not supported
return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND,
req.getID());
}
}
private JSONRPC2Response process(JSONRPC2Request req) {
JSONRPC2Error err = _helper.validateParams(null, req);
if (err != null)
return new JSONRPC2Response(err, req.getID());
if (_context == null) {
return new JSONRPC2Response(new JSONRPC2Error(
JSONRPC2Error.INTERNAL_ERROR.getCode(),
"RouterContext was not initialized. Query failed"),
req.getID());
}
Map<String, Object> inParams = req.getNamedParams();
final Map<String, Object> outParams = new HashMap<String, Object>(4);
if (inParams.containsKey("Shutdown")) {
outParams.put("Shutdown", null);
(new Thread() {
@Override
public void run() {
try {
Thread.sleep(SHUTDOWN_WAIT);
} catch (InterruptedException e) {}
_context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
_context.router().shutdown(Router.EXIT_HARD);
}
}).start();
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("Restart")) {
outParams.put("Restart", null);
(new Thread() {
@Override
public void run() {
try {
Thread.sleep(SHUTDOWN_WAIT);
} catch (InterruptedException e) {}
_context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
_context.router().shutdown(Router.EXIT_HARD_RESTART);
}
}).start();
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("ShutdownGraceful")) {
outParams.put("ShutdownGraceful", null);
(new Thread() {
@Override
public void run() {
try {
Thread.sleep(SHUTDOWN_WAIT);
} catch (InterruptedException e) {}
_context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
_context.router().shutdownGracefully();
}
}).start();
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("RestartGraceful")) {
outParams.put("RestartGraceful", null);
(new Thread() {
@Override
public void run() {
try {
Thread.sleep(SHUTDOWN_WAIT);
} catch (InterruptedException e) {}
_context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
}
}).start();
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("Reseed")) {
outParams.put("Reseed", null);
(new Thread() {
@Override
public void run() {
ReseedChecker reseeder = new ReseedChecker(_context);
reseeder.requestReseed();
}
}).start();
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("FindUpdates")) {
Thread t = new Thread() {
@Override
public void run() {
ClientAppManager clmgr = I2PAppContext.getCurrentContext().clientAppManager();
if (clmgr == null) {
outParams.put("FindUpdates", "ClientAppManager is null");
return;
}
UpdateManager upmgr = (UpdateManager) clmgr.getRegisteredApp(UpdateManager.APP_NAME);
if (upmgr == null) {
outParams.put("FindUpdates", "UpdateManager is null");
return;
}
boolean updateIsAvailable = upmgr.checkAvailable(UpdateType.ROUTER_SIGNED) != null;
outParams.put("FindUpdates", updateIsAvailable);
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {}
return new JSONRPC2Response(outParams, req.getID());
}
if (inParams.containsKey("Update")) {
Thread t = new Thread() {
@Override
public void run() {
ClientAppManager clmgr = I2PAppContext.getCurrentContext().clientAppManager();
if (clmgr == null) {
outParams.put("Update", "ClientAppManager is null");
return;
}
UpdateManager upmgr = (UpdateManager) clmgr.getRegisteredApp(UpdateManager.APP_NAME);
if (upmgr == null) {
outParams.put("Update", "UpdateManager is null");
return;
}
boolean updateStarted = upmgr.update(UpdateType.ROUTER_SIGNED);
if (!updateStarted) {
outParams.put("Update", "Update not started");
return;
}
boolean isUpdating = upmgr.isUpdateInProgress(UpdateType.ROUTER_SIGNED);
while (isUpdating) {
try {
Thread.sleep(100);
} catch (Exception e) {}
isUpdating = upmgr.isUpdateInProgress(UpdateType.ROUTER_SIGNED);
}
outParams.put("Update", upmgr.getStatus());
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {}
return new JSONRPC2Response(outParams, req.getID());
}
return new JSONRPC2Response(outParams, req.getID());
}
public static class UpdateWrapperManagerTask implements Runnable {
private int _exitCode;
public UpdateWrapperManagerTask(int exitCode) {
_exitCode = exitCode;
}
public void run() {
try {
WrapperManager.signalStopped(_exitCode);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,777 @@
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package org.mindrot.jbcrypt;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
/**
* BCrypt implements OpenBSD-style Blowfish password hashing using
* the scheme described in "A Future-Adaptable Password Scheme" by
* Niels Provos and David Mazieres.
* <p>
* This password hashing system tries to thwart off-line password
* cracking using a computationally-intensive hashing algorithm,
* based on Bruce Schneier's Blowfish cipher. The work factor of
* the algorithm is parameterised, so it can be increased as
* computers get faster.
* <p>
* Usage is really simple. To hash a password for the first time,
* call the hashpw method with a random salt, like this:
* <p>
* <code>
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); <br />
* </code>
* <p>
* To check whether a plaintext password matches one that has been
* hashed previously, use the checkpw method:
* <p>
* <code>
* if (BCrypt.checkpw(candidate_password, stored_hash))<br />
* &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("It matches");<br />
* else<br />
* &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("It does not match");<br />
* </code>
* <p>
* The gensalt() method takes an optional parameter (log_rounds)
* that determines the computational complexity of the hashing:
* <p>
* <code>
* String strong_salt = BCrypt.gensalt(10)<br />
* String stronger_salt = BCrypt.gensalt(12)<br />
* </code>
* <p>
* The amount of work increases exponentially (2**log_rounds), so
* each increment is twice as much work. The default log_rounds is
* 10, and the valid range is 4 to 30.
*
* @author Damien Miller
* @version 0.2
*/
public class BCrypt {
// BCrypt parameters
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
private static final int BCRYPT_SALT_LEN = 16;
// Blowfish parameters
private static final int BLOWFISH_NUM_ROUNDS = 16;
// Initial contents of key schedule
private static final int P_orig[] = {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
private static final int S_orig[] = {
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
};
// bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls
// this "ciphertext", but it is really plaintext or an IV. We keep
// the name to make code comparison easier.
static private final int bf_crypt_ciphertext[] = {
0x4f727068, 0x65616e42, 0x65686f6c,
0x64657253, 0x63727944, 0x6f756274
};
// Table for Base64 encoding
static private final char base64_code[] = {
'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9'
};
// Table for Base64 decoding
static private final byte index_64[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
-1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
-1, -1, -1, -1, -1, -1, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, -1, -1, -1, -1, -1
};
// Expanded Blowfish key
private int P[];
private int S[];
/**
* Encode a byte array using bcrypt's slightly-modified base64
* encoding scheme. Note that this is *not* compatible with
* the standard MIME-base64 encoding.
*
* @param d the byte array to encode
* @param len the number of bytes to encode
* @return base64-encoded string
* @exception IllegalArgumentException if the length is invalid
*/
private static String encode_base64(byte d[], int len)
throws IllegalArgumentException {
int off = 0;
StringBuffer rs = new StringBuffer();
int c1, c2;
if (len <= 0 || len > d.length)
throw new IllegalArgumentException ("Invalid len");
while (off < len) {
c1 = d[off++] & 0xff;
rs.append(base64_code[(c1 >> 2) & 0x3f]);
c1 = (c1 & 0x03) << 4;
if (off >= len) {
rs.append(base64_code[c1 & 0x3f]);
break;
}
c2 = d[off++] & 0xff;
c1 |= (c2 >> 4) & 0x0f;
rs.append(base64_code[c1 & 0x3f]);
c1 = (c2 & 0x0f) << 2;
if (off >= len) {
rs.append(base64_code[c1 & 0x3f]);
break;
}
c2 = d[off++] & 0xff;
c1 |= (c2 >> 6) & 0x03;
rs.append(base64_code[c1 & 0x3f]);
rs.append(base64_code[c2 & 0x3f]);
}
return rs.toString();
}
/**
* Look up the 3 bits base64-encoded by the specified character,
* range-checking againt conversion table
* @param x the base64-encoded value
* @return the decoded value of x
*/
private static byte char64(char x) {
if ((int)x < 0 || (int)x > index_64.length)
return -1;
return index_64[(int)x];
}
/**
* Decode a string encoded using bcrypt's base64 scheme to a
* byte array. Note that this is *not* compatible with
* the standard MIME-base64 encoding.
* @param s the string to decode
* @param maxolen the maximum number of bytes to decode
* @return an array containing the decoded bytes
* @throws IllegalArgumentException if maxolen is invalid
*/
private static byte[] decode_base64(String s, int maxolen)
throws IllegalArgumentException {
StringBuffer rs = new StringBuffer();
int off = 0, slen = s.length(), olen = 0;
byte ret[];
byte c1, c2, c3, c4, o;
if (maxolen <= 0)
throw new IllegalArgumentException ("Invalid maxolen");
while (off < slen - 1 && olen < maxolen) {
c1 = char64(s.charAt(off++));
c2 = char64(s.charAt(off++));
if (c1 == -1 || c2 == -1)
break;
o = (byte)(c1 << 2);
o |= (c2 & 0x30) >> 4;
rs.append((char)o);
if (++olen >= maxolen || off >= slen)
break;
c3 = char64(s.charAt(off++));
if (c3 == -1)
break;
o = (byte)((c2 & 0x0f) << 4);
o |= (c3 & 0x3c) >> 2;
rs.append((char)o);
if (++olen >= maxolen || off >= slen)
break;
c4 = char64(s.charAt(off++));
o = (byte)((c3 & 0x03) << 6);
o |= c4;
rs.append((char)o);
++olen;
}
ret = new byte[olen];
for (off = 0; off < olen; off++)
ret[off] = (byte)rs.charAt(off);
return ret;
}
/**
* Blowfish encipher a single 64-bit block encoded as
* two 32-bit halves
* @param lr an array containing the two 32-bit half blocks
* @param off the position in the array of the blocks
*/
private final void encipher(int lr[], int off) {
int i, n, l = lr[off], r = lr[off + 1];
l ^= P[0];
for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) {
// Feistel substitution on left word
n = S[(l >> 24) & 0xff];
n += S[0x100 | ((l >> 16) & 0xff)];
n ^= S[0x200 | ((l >> 8) & 0xff)];
n += S[0x300 | (l & 0xff)];
r ^= n ^ P[++i];
// Feistel substitution on right word
n = S[(r >> 24) & 0xff];
n += S[0x100 | ((r >> 16) & 0xff)];
n ^= S[0x200 | ((r >> 8) & 0xff)];
n += S[0x300 | (r & 0xff)];
l ^= n ^ P[++i];
}
lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
lr[off + 1] = l;
}
/**
* Cycically extract a word of key material
* @param data the string to extract the data from
* @param offp a "pointer" (as a one-entry array) to the
* current offset into data
* @return the next word of material from data
*/
private static int streamtoword(byte data[], int offp[]) {
int i;
int word = 0;
int off = offp[0];
for (i = 0; i < 4; i++) {
word = (word << 8) | (data[off] & 0xff);
off = (off + 1) % data.length;
}
offp[0] = off;
return word;
}
/**
* Initialise the Blowfish key schedule
*/
private void init_key() {
P = (int[])P_orig.clone();
S = (int[])S_orig.clone();
}
/**
* Key the Blowfish cipher
* @param key an array containing the key
*/
private void key(byte key[]) {
int i;
int koffp[] = { 0 };
int lr[] = { 0, 0 };
int plen = P.length, slen = S.length;
for (i = 0; i < plen; i++)
P[i] = P[i] ^ streamtoword(key, koffp);
for (i = 0; i < plen; i += 2) {
encipher(lr, 0);
P[i] = lr[0];
P[i + 1] = lr[1];
}
for (i = 0; i < slen; i += 2) {
encipher(lr, 0);
S[i] = lr[0];
S[i + 1] = lr[1];
}
}
/**
* Perform the "enhanced key schedule" step described by
* Provos and Mazieres in "A Future-Adaptable Password Scheme"
* http://www.openbsd.org/papers/bcrypt-paper.ps
* @param data salt information
* @param key password information
*/
private void ekskey(byte data[], byte key[]) {
int i;
int koffp[] = { 0 }, doffp[] = { 0 };
int lr[] = { 0, 0 };
int plen = P.length, slen = S.length;
for (i = 0; i < plen; i++)
P[i] = P[i] ^ streamtoword(key, koffp);
for (i = 0; i < plen; i += 2) {
lr[0] ^= streamtoword(data, doffp);
lr[1] ^= streamtoword(data, doffp);
encipher(lr, 0);
P[i] = lr[0];
P[i + 1] = lr[1];
}
for (i = 0; i < slen; i += 2) {
lr[0] ^= streamtoword(data, doffp);
lr[1] ^= streamtoword(data, doffp);
encipher(lr, 0);
S[i] = lr[0];
S[i + 1] = lr[1];
}
}
/**
* Perform the central password hashing step in the
* bcrypt scheme
* @param password the password to hash
* @param salt the binary salt to hash with the password
* @param log_rounds the binary logarithm of the number
* of rounds of hashing to apply
* @param cdata the plaintext to encrypt
* @return an array containing the binary hashed password
*/
public byte[] crypt_raw(byte password[], byte salt[], int log_rounds,
int cdata[]) {
int rounds, i, j;
int clen = cdata.length;
byte ret[];
if (log_rounds < 4 || log_rounds > 30)
throw new IllegalArgumentException ("Bad number of rounds");
rounds = 1 << log_rounds;
if (salt.length != BCRYPT_SALT_LEN)
throw new IllegalArgumentException ("Bad salt length");
init_key();
ekskey(salt, password);
for (i = 0; i != rounds; i++) {
key(password);
key(salt);
}
for (i = 0; i < 64; i++) {
for (j = 0; j < (clen >> 1); j++)
encipher(cdata, j << 1);
}
ret = new byte[clen * 4];
for (i = 0, j = 0; i < clen; i++) {
ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
ret[j++] = (byte)(cdata[i] & 0xff);
}
return ret;
}
/**
* Hash a password using the OpenBSD bcrypt scheme
* @param password the password to hash
* @param salt the salt to hash with (perhaps generated
* using BCrypt.gensalt)
* @return the hashed password
*/
public static String hashpw(String password, String salt) {
BCrypt B;
String real_salt;
byte passwordb[], saltb[], hashed[];
char minor = (char)0;
int rounds, off = 0;
StringBuffer rs = new StringBuffer();
if (salt.charAt(0) != '$' || salt.charAt(1) != '2')
throw new IllegalArgumentException ("Invalid salt version");
if (salt.charAt(2) == '$')
off = 3;
else {
minor = salt.charAt(2);
if (minor != 'a' || salt.charAt(3) != '$')
throw new IllegalArgumentException ("Invalid salt revision");
off = 4;
}
// Extract number of rounds
if (salt.charAt(off + 2) > '$')
throw new IllegalArgumentException ("Missing salt rounds");
rounds = Integer.parseInt(salt.substring(off, off + 2));
real_salt = salt.substring(off + 3, off + 25);
try {
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
throw new AssertionError("UTF-8 is not supported");
}
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
B = new BCrypt();
hashed = B.crypt_raw(passwordb, saltb, rounds,
(int[])bf_crypt_ciphertext.clone());
rs.append("$2");
if (minor >= 'a')
rs.append(minor);
rs.append("$");
if (rounds < 10)
rs.append("0");
if (rounds > 30) {
throw new IllegalArgumentException(
"rounds exceeds maximum (30)");
}
rs.append(Integer.toString(rounds));
rs.append("$");
rs.append(encode_base64(saltb, saltb.length));
rs.append(encode_base64(hashed,
bf_crypt_ciphertext.length * 4 - 1));
return rs.toString();
}
/**
* Generate a salt for use with the BCrypt.hashpw() method
* @param log_rounds the log2 of the number of rounds of
* hashing to apply - the work factor therefore increases as
* 2**log_rounds.
* @param random an instance of SecureRandom to use
* @return an encoded salt value
*/
public static String gensalt(int log_rounds, SecureRandom random) {
StringBuffer rs = new StringBuffer();
byte rnd[] = new byte[BCRYPT_SALT_LEN];
random.nextBytes(rnd);
rs.append("$2a$");
if (log_rounds < 10)
rs.append("0");
if (log_rounds > 30) {
throw new IllegalArgumentException(
"log_rounds exceeds maximum (30)");
}
rs.append(Integer.toString(log_rounds));
rs.append("$");
rs.append(encode_base64(rnd, rnd.length));
return rs.toString();
}
/**
* Generate a salt for use with the BCrypt.hashpw() method
* @param log_rounds the log2 of the number of rounds of
* hashing to apply - the work factor therefore increases as
* 2**log_rounds.
* @return an encoded salt value
*/
public static String gensalt(int log_rounds) {
return gensalt(log_rounds, new SecureRandom());
}
/**
* Generate a salt for use with the BCrypt.hashpw() method,
* selecting a reasonable default for the number of hashing
* rounds to apply
* @return an encoded salt value
*/
public static String gensalt() {
return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS);
}
/**
* Check that a plaintext password matches a previously hashed
* one
* @param plaintext the plaintext password to verify
* @param hashed the previously-hashed password
* @return true if the passwords match, false otherwise
*/
public static boolean checkpw(String plaintext, String hashed) {
byte hashed_bytes[];
byte try_bytes[];
try {
String try_pw = hashpw(plaintext, hashed);
hashed_bytes = hashed.getBytes("UTF-8");
try_bytes = try_pw.getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
return false;
}
if (hashed_bytes.length != try_bytes.length)
return false;
byte ret = 0;
for (int i = 0; i < try_bytes.length; i++)
ret |= hashed_bytes[i] ^ try_bytes[i];
return ret == 0;
}
}

15
apps/i2pcontrol/web.xml Normal file
View File

@@ -0,0 +1,15 @@
<?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">
<servlet>
<servlet-name>net.i2p.i2pcontrol.servlets.JSONRPC2Servlet</servlet-name>
<servlet-class>net.i2p.i2pcontrol.servlets.JSONRPC2Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>net.i2p.i2pcontrol.servlets.JSONRPC2Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -1,4 +1,6 @@
apply plugin: 'war'
plugins {
id 'war'
}
sourceSets {
main {

View File

@@ -25,9 +25,11 @@
</depend>
</target>
<!-- only used if not set by a higher build.xml -->
<property name="javac.compilerargs" value="" />
<property name="javac.version" value="1.7" />
<property name="require.gettext" value="true" />
<property name="manifest.classpath.name" value="Class-Path" />
<condition property="no.bundle">
<isfalse value="${require.gettext}" />
@@ -79,7 +81,7 @@
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/web/* **/messages_*.class, **/standalone/*">
<manifest>
<attribute name="Main-Class" value="org.klomp.snark.CommandLine" />
<attribute name="Class-Path" value="i2p.jar mstreaming.jar streaming.jar" />
<attribute name="${manifest.classpath.name}" value="i2p.jar mstreaming.jar streaming.jar" />
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
@@ -202,7 +204,6 @@
<fileset dir="build/obj" includes="**/standalone/*.class" />
<zipfileset src="build/i2psnark.jar" />
<zipfileset src="../../../core/java/build/i2p.jar" />
<zipfileset src="../../jetty/jettylib/commons-logging.jar" />
<!-- without this we get a warning about 'no JSP support' but that's it
<zipfileset src="../../jetty/jettylib/jasper-runtime.jar" />
-->
@@ -249,12 +250,6 @@
<fileset dir="../../../installer/resources/themes/snark/" />
</copy>
<replace dir="build/standalone-resources/.resources/themes/snark"
summary="true"
token="url(/themes/console/classic/images/"
value="url(/i2psnark/.resources/themes/snark/classic/images/" >
<include name="**/*.css" />
</replace>
<replace dir="build/standalone-resources/.resources/themes/snark"
summary="true"
token="url(/themes/console/dark/images/"
@@ -297,8 +292,6 @@
todir="build/standalone-resources/.resources/themes/snark/dark/images" />
<copy file="../../../installer/resources/themes/console/images/info/errortriangle.png"
todir="build/standalone-resources/.resources/themes/snark/ubergine/images" />
<copy file="../../../installer/resources/themes/console/classic/images/bg0.png"
todir="build/standalone-resources/.resources/themes/snark/classic/images" />
<mkdir dir="build/standalone-resources/.resources/js" />
<copy file="../../routerconsole/jsp/js/ajax.js" todir="build/standalone-resources/.resources/js" />

View File

@@ -99,7 +99,7 @@ public class I2PSnarkUtil {
_baseName = baseName;
_opts = new HashMap<String, String>();
//setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", 7654, null);
setI2CPConfig("127.0.0.1", I2PClient.DEFAULT_LISTEN_PORT, null);
_banlist = new ConcurrentHashSet<Hash>();
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
_maxUpBW = SnarkManager.DEFAULT_MAX_UP_BW;

View File

@@ -112,7 +112,7 @@ class PartialPiece implements Comparable<PartialPiece> {
* as set by setDownloaded() or read().
*/
public Request getRequest() {
public synchronized Request getRequest() {
return new Request(this, this.off, Math.min(this.pclen - this.off, PeerState.PARTSIZE));
}
@@ -131,7 +131,7 @@ class PartialPiece implements Comparable<PartialPiece> {
/**
* How many bytes are good - as set by setDownloaded() or read()
*/
public int getDownloaded() {
public synchronized int getDownloaded() {
return this.off;
}
@@ -141,7 +141,7 @@ class PartialPiece implements Comparable<PartialPiece> {
* Any chunks after a 'hole' will be lost.
* @since 0.9.1
*/
public void setDownloaded(int offset) {
public synchronized void setDownloaded(int offset) {
this.off = offset;
}

View File

@@ -79,6 +79,7 @@ public class Peer implements Comparable<Peer>
private long uploaded_old[] = {-1,-1,-1};
private long downloaded_old[] = {-1,-1,-1};
private static final byte[] HANDSHAKE = DataHelper.getASCII("BitTorrent protocol");
// bytes per bt spec: 0011223344556677
private static final long OPTION_EXTENSION = 0x0000000000100000l;
private static final long OPTION_FAST = 0x0000000000000004l;
@@ -343,8 +344,8 @@ public class Peer implements Comparable<Peer>
dout = new DataOutputStream(out);
// Handshake write - header
dout.write(19);
dout.write("BitTorrent protocol".getBytes("UTF-8"));
dout.write(HANDSHAKE.length);
dout.write(HANDSHAKE);
// Handshake write - options
long myOptions = OPTION_EXTENSION;
// we can't handle HAVE_ALL or HAVE_NONE if we don't know the number of pieces
@@ -365,17 +366,15 @@ public class Peer implements Comparable<Peer>
// Handshake read - header
byte b = din.readByte();
if (b != 19)
if (b != HANDSHAKE.length)
throw new IOException("Handshake failure, expected 19, got "
+ (b & 0xff) + " on " + sock);
byte[] bs = new byte[19];
byte[] bs = new byte[HANDSHAKE.length];
din.readFully(bs);
String bittorrentProtocol = new String(bs, "UTF-8");
if (!"BitTorrent protocol".equals(bittorrentProtocol))
if (!Arrays.equals(HANDSHAKE, bs))
throw new IOException("Handshake failure, expected "
+ "'BitTorrent protocol', got '"
+ bittorrentProtocol + "'");
+ "'BitTorrent protocol'");
// Handshake read - options
options = din.readLong();
@@ -684,6 +683,13 @@ public class Peer implements Comparable<Peer>
return -1; //"no state";
}
}
/** @since 0.9.36 */
public long getMaxInactiveTime() {
return isCompleted() && !isInteresting() ?
PeerCoordinator.MAX_SEED_INACTIVE :
PeerCoordinator.MAX_INACTIVE;
}
/**
* Send keepalive

View File

@@ -96,7 +96,7 @@ class PeerCheckerTask implements Runnable
continue;
}
if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) {
if (peer.getInactiveTime() > peer.getMaxInactiveTime()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Disconnecting peer idle " +
DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer);

View File

@@ -75,6 +75,7 @@ class PeerCoordinator implements PeerListener
final static long CHECK_PERIOD = 40*1000; // 40 seconds
final static int MAX_UPLOADERS = 8;
public static final long MAX_INACTIVE = 8*60*1000;
public static final long MAX_SEED_INACTIVE = 2*60*1000;
/**
* Approximation of the number of current uploaders (unchoked peers),
@@ -496,7 +497,7 @@ class PeerCoordinator implements PeerListener
synchronized(peers)
{
Peer old = peerIDInList(peer.getPeerID(), peers);
if ( (old != null) && (old.getInactiveTime() > MAX_INACTIVE) ) {
if (old != null && old.getInactiveTime() > old.getMaxInactiveTime()) {
// idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
if (_log.shouldLog(Log.WARN))
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
@@ -592,8 +593,10 @@ class PeerCoordinator implements PeerListener
// thus there is an additional check in connected()
need_more = (!peer.isConnected()) && peersize < getMaxConnections();
// Check if we already have this peer before we build the connection
Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = need_more && ((old == null) || (old.getInactiveTime() > MAX_INACTIVE));
if (need_more) {
Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = old == null || old.getInactiveTime() > old.getMaxInactiveTime();
}
}
if (need_more)
@@ -629,9 +632,9 @@ class PeerCoordinator implements PeerListener
}
if (_log.shouldLog(Log.DEBUG)) {
if (peer.isConnected())
_log.info("Add peer already connected: " + peer);
_log.debug("Add peer already connected: " + peer);
else
_log.info("Connections: " + peersize + "/" + getMaxConnections()
_log.debug("Connections: " + peersize + "/" + getMaxConnections()
+ " not accepting extra peer: " + peer);
}
return false;

View File

@@ -25,12 +25,16 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.Log;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
class PeerState implements DataLoader
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
@@ -242,14 +246,33 @@ class PeerState implements DataLoader
} // synch
boolean interest = listener.gotBitField(peer, bitfield);
setInteresting(interest);
if (bitfield.complete() && !interest) {
// They are seeding and we are seeding,
// why did they contact us? (robert)
// Dump them quick before we send our whole bitmap
// If we both support comments, allow it
if (listener.getUtil().utCommentsEnabled()) {
Map<String, BEValue> handshake = peer.getHandshakeMap();
if (handshake != null) {
BEValue bev = handshake.get("m");
if (bev != null) {
try {
if (bev.getMap().get(ExtensionHandler.TYPE_COMMENT) != null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Allowing seed that connects to seeds for comments: " + peer);
setInteresting(interest);
return;
}
} catch (InvalidBEncodingException ibee) {}
}
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Disconnecting seed that connects to seeds: " + peer);
peer.disconnect(true);
} else {
setInteresting(interest);
}
}
@@ -546,7 +569,7 @@ class PeerState implements DataLoader
synchronized(pp) {
int dl = pp.getDownloaded();
if (req.off != dl)
req = new Request(pp, dl, 1);
req = new Request(pp, dl);
}
rv.add(req);
}

View File

@@ -52,6 +52,25 @@ class Request
throw new IndexOutOfBoundsException("Illegal Request " + toString());
}
/**
* Dummy Request for PeerState.returnPartialPieces().
* len will be zero.
*
* @param piece Piece number requested.
* @param off the offset in the array.
* @since 0.9.36
*/
Request(PartialPiece piece, int off)
{
this.piece = piece;
this.off = off;
this.len = 0;
// Sanity check
if (off < 0 || off > piece.getLength())
throw new IndexOutOfBoundsException("Illegal Request " + toString());
}
/**
* @since 0.9.1
*/

View File

@@ -300,20 +300,25 @@ public class Snark
/**
* multitorrent
*
* Will not start itself. Caller must call startTorrent() if desired.
*
* @throws RuntimeException via fatal()
*/
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener,
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
ConnectionAcceptor connectionAcceptor, boolean start, String rootDir)
ConnectionAcceptor connectionAcceptor, String rootDir)
{
this(util, torrent, ip, user_port, slistener, clistener, complistener,
peerCoordinatorSet, connectionAcceptor, start, rootDir, null);
peerCoordinatorSet, connectionAcceptor, rootDir, null);
}
/**
* multitorrent
*
* Will not start itself. Caller must call startTorrent() if desired.
*
* @param baseFile if null, use rootDir/torrentName; if non-null, use it instead
* @throws RuntimeException via fatal()
* @since 0.9.11
@@ -321,7 +326,7 @@ public class Snark
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener,
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
ConnectionAcceptor connectionAcceptor, boolean start, String rootDir, File baseFile)
ConnectionAcceptor connectionAcceptor, String rootDir, File baseFile)
{
if (slistener == null)
slistener = this;
@@ -482,14 +487,13 @@ public class Snark
savedUploaded = (completeListener != null) ? completeListener.getSavedUploaded(this) : 0;
if (completeListener != null)
_comments = completeListener.getSavedComments(this);
if (start)
startTorrent();
}
/**
* multitorrent, magnet
*
* Will not start itself. Caller must call startTorrent() if desired.
*
* @param torrent a fake name for now (not a file name)
* @param ih 20-byte info hash
* @param trackerURL may be null
@@ -498,7 +502,7 @@ public class Snark
*/
public Snark(I2PSnarkUtil util, String torrent, byte[] ih, String trackerURL,
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
ConnectionAcceptor connectionAcceptor, boolean start, String rootDir)
ConnectionAcceptor connectionAcceptor, String rootDir)
{
completeListener = complistener;
_util = util;
@@ -516,9 +520,6 @@ public class Snark
// All we have is an infoHash
// meta remains null
// storage remains null
if (start)
startTorrent();
}
private static byte[] generateID() {

View File

@@ -28,6 +28,7 @@ import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import net.i2p.client.I2PClient;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
@@ -105,6 +106,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
private static final String PROP_META_UPLOADED = "uploaded";
private static final String PROP_META_ADDED = "added";
private static final String PROP_META_COMPLETED = "completed";
private static final String PROP_META_INORDER = "inOrder";
private static final String PROP_META_MAGNET = "magnet";
private static final String PROP_META_MAGNET_DN = "magnet_dn";
private static final String PROP_META_MAGNET_TR = "magnet_tr";
@@ -131,6 +133,9 @@ public class SnarkManager implements CompleteListener, ClientApp {
public static final String RC_PROP_UNIVERSAL_THEMING = "routerconsole.universal.theme";
public static final String PROP_THEME = "i2psnark.theme";
public static final String DEFAULT_THEME = "ubergine";
/** From CSSHelper */
private static final String PROP_DISABLE_OLD = "routerconsole.disableOldThemes";
private static final boolean DEFAULT_DISABLE_OLD = true;
/** @since 0.9.32 */
public static final String PROP_COLLAPSE_PANELS = "i2psnark.collapsePanels";
private static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
@@ -197,7 +202,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
public static final Set<String> DEFAULT_TRACKER_ANNOUNCES;
/** host names for config form */
public static final Set<String> KNOWN_OPENTRACKERS = new HashSet<String>(Arrays.asList(new String[] {
static final Set<String> KNOWN_OPENTRACKERS = new HashSet<String>(Arrays.asList(new String[] {
"tracker.welterde.i2p", "cfmqlafjfmgkzbt4r3jsfyhgsr5abgxryl6fnz3d3y5a365di5aa.b32.i2p",
"opentracker.dg2.i2p", "w7tpbzncbcocrqtwwm3nezhnnsw4ozadvi2hmvzdhrqzfxfum7wa.b32.i2p",
"tracker.thebland.i2p", "s5ikrdyjwbcgxmqetxb3nyheizftms7euacuub2hic7defkh3xhq.b32.i2p",
@@ -781,7 +786,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
if (!_config.containsKey(PROP_I2CP_HOST))
_config.setProperty(PROP_I2CP_HOST, "127.0.0.1");
if (!_config.containsKey(PROP_I2CP_PORT))
_config.setProperty(PROP_I2CP_PORT, "7654");
_config.setProperty(PROP_I2CP_PORT, Integer.toString(I2PClient.DEFAULT_LISTEN_PORT));
if (!_config.containsKey(PROP_I2CP_OPTS))
_config.setProperty(PROP_I2CP_OPTS, "inbound.length=3 outbound.length=3" +
" inbound.quantity=" + DEFAULT_TUNNEL_QUANTITY +
@@ -831,7 +836,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
* @return String -- the current theme
*/
public String getTheme() {
String theme = _config.getProperty(PROP_THEME);
String theme;
if (getUniversalTheming()) {
// Fetch routerconsole theme (or use our default if it doesn't exist)
theme = _context.getProperty(RC_PROP_THEME, DEFAULT_THEME);
@@ -839,8 +844,10 @@ public class SnarkManager implements CompleteListener, ClientApp {
String[] themes = getThemes();
boolean themeExists = false;
for (int i = 0; i < themes.length; i++) {
if (themes[i].equals(theme))
if (themes[i].equals(theme)) {
themeExists = true;
break;
}
}
if (!themeExists) {
// Since the default is not "light", explicitly check if universal theme is "classic"
@@ -850,6 +857,16 @@ public class SnarkManager implements CompleteListener, ClientApp {
theme = DEFAULT_THEME;
_config.setProperty(PROP_THEME, DEFAULT_THEME);
}
} else {
theme = _config.getProperty(PROP_THEME, DEFAULT_THEME);
}
// remap deprecated themes
if (theme.equals("midnight")) {
if (_context.getProperty(PROP_DISABLE_OLD, DEFAULT_DISABLE_OLD))
theme = "dark";
} else if (theme.equals("classic")) {
if (_context.getProperty(PROP_DISABLE_OLD, DEFAULT_DISABLE_OLD))
theme = "light";
}
return theme;
}
@@ -861,21 +878,24 @@ public class SnarkManager implements CompleteListener, ClientApp {
public String[] getThemes() {
String[] themes;
if (_context.isRouterContext()) {
// "docs/themes/snark/"
File dir = new File(_context.getBaseDir(), "docs/themes/snark");
FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } };
// Walk the themes dir, collecting the theme names, and append them to the map
File[] dirnames = dir.listFiles(fileFilter);
if (dirnames != null) {
themes = new String[dirnames.length];
for(int i = 0; i < dirnames.length; i++) {
themes[i] = dirnames[i].getName();
List<String> th = new ArrayList<String>(dirnames.length);
boolean skipOld = _context.getProperty(PROP_DISABLE_OLD, DEFAULT_DISABLE_OLD);
for (int i = 0; i < dirnames.length; i++) {
String name = dirnames[i].getName();
if (skipOld && (name.equals("midnight") || name.equals("classic")))
continue;
th.add(name);
}
themes = th.toArray(new String[th.size()]);
} else {
themes = new String[0];
}
} else {
themes = new String[] { "classic", "dark", "light", "midnight", "ubergine", "vanilla" };
themes = new String[] { "dark", "light", "ubergine", "vanilla" };
}
return themes;
}
@@ -892,7 +912,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
private void updateConfig() {
String i2cpHost = _config.getProperty(PROP_I2CP_HOST);
int i2cpPort = getInt(PROP_I2CP_PORT, 7654);
int i2cpPort = getInt(PROP_I2CP_PORT, I2PClient.DEFAULT_LISTEN_PORT);
String opts = _config.getProperty(PROP_I2CP_OPTS);
Map<String, String> i2cpOpts = new HashMap<String, String>();
if (opts != null) {
@@ -1555,11 +1575,13 @@ public class SnarkManager implements CompleteListener, ClientApp {
_log.info("New Snark, torrent: " + filename + " base: " + baseFile);
torrent = new Snark(_util, filename, null, -1, null, null, this,
_peerCoordinatorSet, _connectionAcceptor,
shouldAutoStart(), dataDir.getPath(), baseFile);
dataDir.getPath(), baseFile);
loadSavedFilePriorities(torrent);
synchronized (_snarks) {
_snarks.put(filename, torrent);
}
if (shouldAutoStart())
torrent.startTorrent();
} catch (IOException ioe) {
// close before rename/delete for windows
if (fis != null) try { fis.close(); fis = null; } catch (IOException ioe2) {}
@@ -1660,7 +1682,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
String dirPath = dataDir != null ? dataDir.getAbsolutePath() : getDataDir().getPath();
Snark torrent = new Snark(_util, name, ih, trackerURL, listener,
_peerCoordinatorSet, _connectionAcceptor,
false, dirPath);
dirPath);
synchronized (_snarks) {
Snark snark = getTorrentByInfoHash(ih);
@@ -1757,7 +1779,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return false;
} else if (bitfield != null) {
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
saveTorrentStatus(metainfo, bitfield, null, false, baseFile, true, 0, true); // no file priorities
}
// so addTorrent won't recheck
if (filename == null) {
@@ -1896,19 +1918,21 @@ public class SnarkManager implements CompleteListener, ClientApp {
return;
Properties config = getConfig(snark);
String pri = config.getProperty(PROP_META_PRIORITY);
if (pri == null)
return;
int filecount = metainfo.getFiles().size();
int[] rv = new int[filecount];
String[] arr = DataHelper.split(pri, ",");
for (int i = 0; i < filecount && i < arr.length; i++) {
if (arr[i].length() > 0) {
try {
rv[i] = Integer.parseInt(arr[i]);
} catch (Throwable t) {}
if (pri != null) {
int filecount = metainfo.getFiles().size();
int[] rv = new int[filecount];
String[] arr = DataHelper.split(pri, ",");
for (int i = 0; i < filecount && i < arr.length; i++) {
if (arr[i].length() > 0) {
try {
rv[i] = Integer.parseInt(arr[i]);
} catch (Throwable t) {}
}
}
storage.setFilePriorities(rv);
}
storage.setFilePriorities(rv);
boolean inOrder = Boolean.parseBoolean(config.getProperty(PROP_META_INORDER));
storage.setInOrder(inOrder);
}
/**
@@ -2015,7 +2039,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
Storage storage = snark.getStorage();
if (meta == null || storage == null)
return;
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(), storage.getInOrder(),
storage.getBase(), storage.getPreserveFileNames(),
snark.getUploaded(), snark.isStopped(), comments);
}
@@ -2032,24 +2056,24 @@ public class SnarkManager implements CompleteListener, ClientApp {
* @param priorities may be null
* @param base may be null
*/
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
File base, boolean preserveNames, long uploaded, boolean stopped) {
saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded, stopped, null);
saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, stopped, null);
}
/*
* @param comments null for no change
* @since 0.9.31
*/
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
File base, boolean preserveNames, long uploaded, boolean stopped,
Boolean comments) {
synchronized (_configLock) {
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded, stopped, comments);
locked_saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, stopped, comments);
}
}
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
File base, boolean preserveNames, long uploaded, boolean stopped,
Boolean comments) {
byte[] ih = metainfo.getInfoHash();
@@ -2075,6 +2099,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
config.setProperty(PROP_META_UPLOADED, Long.toString(uploaded));
boolean running = !stopped;
config.setProperty(PROP_META_RUNNING, Boolean.toString(running));
config.setProperty(PROP_META_INORDER, Boolean.toString(inOrder));
if (base != null)
config.setProperty(PROP_META_BASE, base.getAbsolutePath());
if (comments != null)
@@ -2093,7 +2118,9 @@ public class SnarkManager implements CompleteListener, ClientApp {
// generate string like -5,,4,3,,,,,,-2 where no number is zero.
StringBuilder buf = new StringBuilder(2 * priorities.length);
for (int i = 0; i < priorities.length; i++) {
if (priorities[i] != 0)
// only output if !inOrder || !skipped so the string isn't too long
if (priorities[i] != 0 &&
(!inOrder || priorities[i] < 0))
buf.append(Integer.toString(priorities[i]));
if (i != priorities.length - 1)
buf.append(',');
@@ -2441,7 +2468,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
MetaInfo meta = snark.getMetaInfo();
Storage storage = snark.getStorage();
if (meta != null && storage != null)
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(), storage.getInOrder(),
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded(),
snark.isStopped());
}
@@ -2465,7 +2492,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
snark.stopTorrent();
return null;
}
saveTorrentStatus(meta, storage.getBitField(), null,
saveTorrentStatus(meta, storage.getBitField(), null, false,
storage.getBase(), storage.getPreserveFileNames(), 0,
snark.isStopped());
// temp for addMessage() in case canonical throws
@@ -2676,6 +2703,14 @@ public class SnarkManager implements CompleteListener, ClientApp {
return rv;
}
/**
* Has the default tracker list been modified?
* @since 0.9.35
*/
public boolean hasModifiedTrackers() {
return _config.containsKey(PROP_TRACKERS);
}
/** @since 0.9 */
private void initTrackerMap() {
String trackers = _config.getProperty(PROP_TRACKERS);

View File

@@ -25,11 +25,14 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.security.MessageDigest;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -72,6 +75,7 @@ public class Storage implements Closeable
private final boolean _preserveFileNames;
private boolean changed;
private volatile boolean _isChecking;
private boolean _inOrder;
private final AtomicInteger _allocateCount = new AtomicInteger();
private final AtomicInteger _checkProgress = new AtomicInteger();
@@ -82,6 +86,8 @@ public class Storage implements Closeable
/** The maximum number of pieces in a torrent. */
public static final int MAX_PIECES = 32*1024;
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
public static final int PRIORITY_SKIP = -9;
public static final int PRIORITY_NORMAL = 0;
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap<String, String>();
@@ -145,7 +151,7 @@ public class Storage implements Closeable
_torrentFiles = getFiles(baseFile);
long total = 0;
ArrayList<Long> lengthsList = new ArrayList<Long>();
ArrayList<Long> lengthsList = new ArrayList<Long>(_torrentFiles.size());
for (TorrentFile tf : _torrentFiles)
{
long length = tf.length;
@@ -178,7 +184,7 @@ public class Storage implements Closeable
bitfield = new BitField(pieces);
needed = 0;
List<List<String>> files = new ArrayList<List<String>>();
List<List<String>> files = new ArrayList<List<String>>(_torrentFiles.size());
for (TorrentFile tf : _torrentFiles)
{
List<String> file = new ArrayList<String>();
@@ -434,9 +440,9 @@ public class Storage implements Closeable
*/
public int getPriority(int fileIndex) {
if (complete() || metainfo.getFiles() == null)
return 0;
return PRIORITY_NORMAL;
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
return 0;
return PRIORITY_NORMAL;
return _torrentFiles.get(fileIndex).priority;
}
@@ -482,7 +488,7 @@ public class Storage implements Closeable
void setFilePriorities(int[] p) {
if (p == null) {
for (TorrentFile tf : _torrentFiles) {
tf.priority = 0;
tf.priority = PRIORITY_NORMAL;
}
} else {
int sz = _torrentFiles.size();
@@ -494,17 +500,71 @@ public class Storage implements Closeable
}
}
/**
* @return as last set, default false
* @since 0.9.36
*/
public boolean getInOrder() {
return _inOrder;
}
/**
* Call AFTER setFilePriorites() so we know what's skipped
* @param yes enable or not
* @since 0.9.36
*/
public void setInOrder(boolean yes) {
if (yes == _inOrder)
return;
_inOrder = yes;
if (complete())
return;
if (yes) {
List<TorrentFile> sorted = _torrentFiles;
int sz = sorted.size();
if (sz > 1) {
sorted = new ArrayList<TorrentFile>(sorted);
Collections.sort(sorted, new FileNameComparator());
}
for (int i = 0; i < sz; i++) {
TorrentFile tf = sorted.get(i);
// higher number is higher priority
if (tf.priority >= PRIORITY_NORMAL)
tf.priority = sz - i;
}
} else {
for (TorrentFile tf : _torrentFiles) {
if (tf.priority > PRIORITY_NORMAL)
tf.priority = PRIORITY_NORMAL;
}
}
}
/**
* Sort with locale comparator.
* (not using TorrentFile.compareTo())
* @since 0.9.36
*/
private static class FileNameComparator implements Comparator<TorrentFile>, Serializable {
private final Collator c = Collator.getInstance();
public int compare(TorrentFile l, TorrentFile r) {
return c.compare(l.toString(), r.toString());
}
}
/**
* Call setPriority() for all changed files first,
* then call this.
* Set the piece priority to the highest priority
* of all files spanning the piece.
* Caller must pass array to the PeerCoordinator.
* @return null on error, if complete, or if only one file
* @return null on error, if complete, or if only one file and inOrder not set.
* @since 0.8.1
*/
public int[] getPiecePriorities() {
if (complete() || metainfo.getFiles() == null)
if (complete() || (metainfo.getFiles() == null && !_inOrder))
return null;
int[] rv = new int[metainfo.getPieces()];
int file = 0;
@@ -523,6 +583,25 @@ public class Storage implements Closeable
}
rv[i] = pri;
}
if (_inOrder) {
// Do a second pass to set the priority of the pieces within each file
// this only works because MAX_PIECES * MAX_FILES_PER_TORRENT < Integer.MAX_VALUE
// the base file priority
int pri = PRIORITY_SKIP;
for (int i = 0; i < rv.length; i++) {
int val = rv[i];
if (val <= PRIORITY_NORMAL)
continue;
if (val != pri) {
pri = val;
// new file
rv[i] *= MAX_PIECES;
} else {
// same file, decrement priority from previous piece
rv[i] = rv[i-1] - 1;
}
}
}
return rv;
}
@@ -544,7 +623,7 @@ public class Storage implements Closeable
long rv = 0;
final int end = pri.length - 1;
for (int i = 0; i <= end; i++) {
if (pri[i] <= -9 && !bitfield.get(i)) {
if (pri[i] <= PRIORITY_SKIP && !bitfield.get(i)) {
rv += (i != end) ? piece_size : metainfo.getPieceLength(i);
}
}
@@ -709,9 +788,29 @@ public class Storage implements Closeable
{
if (_torrentFiles.isEmpty())
throw new IOException("Storage not checked yet");
for (TorrentFile tf : _torrentFiles) {
if (!tf.RAFfile.exists())
throw new IOException("File does not exist: " + tf);
for (int i = 0; i < _torrentFiles.size(); i++) {
TorrentFile tf = _torrentFiles.get(i);
if (!tf.RAFfile.exists()) {
// File should exist when we get here, but could have vanished
List<List<String>> files = metainfo.getFiles();
if (files != null) {
createFileFromNames(_base, files.get(i), _util.getFilesPublic());
} else {
if (!_base.createNewFile())
throw new IOException("File '" + tf.name + "' was deleted, unable to recreate");
}
synchronized(tf) {
tf.allocateFile();
// close as we go so we don't run out of file descriptors
try {
tf.closeRAF();
} catch (IOException ioe) {}
}
String msg = "File '" + tf.name + "' was deleted, must be downloaded again";
if (listener != null)
listener.addMessage(msg);
_log.error(msg);
}
}
}
@@ -944,18 +1043,32 @@ public class Storage implements Closeable
// Make sure all files are available and of correct length
// The files should all exist as they have been created with zero length by createFilesFromNames()
long lengthProgress = 0;
for (TorrentFile tf : _torrentFiles)
{
for (int i = 0; i < _torrentFiles.size(); i++) {
TorrentFile tf = _torrentFiles.get(i);
long length = tf.RAFfile.length();
lengthProgress += tf.length;
if(tf.RAFfile.exists() && length == tf.length)
{
boolean exists = tf.RAFfile.exists();
if (exists && length == tf.length) {
if (listener != null)
listener.storageAllocated(this, length);
_checkProgress.set(0);
resume = true; // XXX Could dynamicly check
} else if (length == 0) {
if (!exists) {
// File should exist when we get here, but could have vanished
// and we're now doing a recheck
List<List<String>> files = metainfo.getFiles();
if (files != null) {
createFileFromNames(_base, files.get(i), _util.getFilesPublic());
} else {
if (!_base.createNewFile())
throw new IOException("File '" + tf.name + "' was deleted, unable to recreate");
}
String msg = "File '" + tf.name + "' was deleted, must be downloaded again";
if (listener != null)
listener.addMessage(msg);
_log.error(msg);
}
else if (length == 0) {
changed = true;
synchronized(tf) {
allocateFile(tf);
@@ -1427,6 +1540,8 @@ public class Storage implements Closeable
* Sets isSparse[nr] = true. balloonFile(nr) should be called later to
* defrag the file.
*
* File MUST exist or will throw IOE
*
* This calls openRAF(); caller must synchronize and call closeRAF().
*/
public synchronized void allocateFile() throws IOException {

View File

@@ -10,7 +10,11 @@ import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
/**
* Store comments
* Store a single comment and/or rating.
* Unmodifiable except for marking as hidden.
* Stores a one-second timestamp but designed so identical
* comments within a certain time frame (bucket) are equal.
* Don't store in a plain set - see equals().
*
* @since 0.9.31
*/
@@ -30,6 +34,7 @@ public class Comment implements Comparable<Comment> {
private static final int MAX_TEXT_LEN = 512;
private static final int BUCKET_SIZE = 10*60*1000;
private static final long TIME_SHRINK = 1000L;
private static final int MAX_SKEW = (int) (BUCKET_SIZE / TIME_SHRINK);
// 1/1/2005
private static final long TIME_OFFSET = 1104537600000L;
@@ -181,26 +186,29 @@ public class Comment implements Comparable<Comment> {
}
}
/**
* @return bucket number
*/
@Override
public int hashCode() {
return time / (BUCKET_SIZE / (int) TIME_SHRINK);
return time / MAX_SKEW;
}
/**
* Comments in the same 10-minute bucket and otherwise equal
* are considered equal. This will result in duplicates
* near the border.
* Comments within 10 minutes (not necessarily in same bucket)
* and otherwise equal are considered equal.
* Violates contract, as equal objects may have different hashcodes and
* be in adjacent buckets.
*/
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Comment)) return false;
Comment c = (Comment) o;
return rating == c.rating &&
eq(text, c.text) &&
eq(name, c.name) &&
hashCode() == c.hashCode();
int tdiff = time - c.time;
if (tdiff > MAX_SKEW || tdiff < 0 - MAX_SKEW)
return false;
return equalsIgnoreTimestamp(c);
}
/**

View File

@@ -58,7 +58,7 @@ public class CommentSet extends AbstractSet<Comment> {
// Assume most comments are short or null.
private static final int MAX_TOTAL_TEXT_LEN = MAX_SIZE * 16;
public CommentSet() {
private CommentSet() {
super();
map = new HashMap<Integer, List<Comment>>(4);
}
@@ -80,7 +80,7 @@ public class CommentSet extends AbstractSet<Comment> {
try {
br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file)), "UTF-8"));
String line = null;
while ( (line = br.readLine()) != null) {
while ((line = br.readLine()) != null) {
Comment c = Comment.fromPersistentString(line);
if (c != null)
add(c);
@@ -129,7 +129,18 @@ public class CommentSet extends AbstractSet<Comment> {
// If isMine and no text and rating changed, don't bother
if (c.isMine() && c.getText() == null && c.getRating() == myRating)
return false;
Integer hc = Integer.valueOf(c.hashCode());
int hCode = c.hashCode();
// check previous and next buckets
Integer phc = Integer.valueOf(hCode - 1);
List<Comment> plist = map.get(phc);
if (plist != null && plist.contains(c))
return false;
Integer nhc = Integer.valueOf(hCode + 1);
List<Comment> nxlist = map.get(nhc);
if (nxlist != null && nxlist.contains(c))
return false;
// check this bucket
Integer hc = Integer.valueOf(hCode);
List<Comment> list = map.get(hc);
if (list == null) {
list = Collections.singletonList(c);

View File

@@ -1034,6 +1034,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
opts.setDate(_context.clock().now() + 60*1000);
opts.setTagsToSend(SEND_CRYPTO_TAGS);
opts.setTagThreshold(LOW_CRYPTO_TAGS);
opts.setGzip(false);
if (!repliable)
opts.setSendLeaseSet(false);
try {

View File

@@ -28,6 +28,7 @@ public class ConfigUIHelper {
*/
private static final String langs[][] = {
{ "ar", "lang_ar", "Arabic ﻉﺮﺒﻳﺓ", null },
{ "az", "az", "Azerbaijani", null },
{ "cs", "cz", "Čeština", null },
{ "zh", "cn", "Chinese 中文", null },
//{ "zh_TW", "tw", "Chinese 中文", "Taiwan" },

View File

@@ -157,12 +157,15 @@ class BasicServlet extends HttpServlet
*/
public File getResource(String pathInContext)
{
if (_resourceBase==null)
return null;
File r = null;
if (!pathInContext.contains("..") &&
!pathInContext.endsWith("/")) {
File f = new File(_resourceBase, pathInContext);
File f;
synchronized (this) {
if (_resourceBase==null)
return null;
f = new File(_resourceBase, pathInContext);
}
if (f.exists())
r = f;
}
@@ -178,8 +181,6 @@ class BasicServlet extends HttpServlet
*/
public HttpContent getContent(String pathInContext)
{
if (_resourceBase==null)
return null;
HttpContent r = null;
if (_warBase != null && pathInContext.startsWith(_warBase)) {
r = new JarContent(pathInContext);

View File

@@ -72,7 +72,7 @@ public class FetchAndAdd extends Snark implements EepGet.StatusListener, Runnabl
public FetchAndAdd(I2PAppContext ctx, SnarkManager mgr, String url, File dataDir) {
// magnet constructor
super(mgr.util(), "Torrent download",
null, null, null, null, null, false, null);
null, null, null, null, null, null);
_ctx = ctx;
_log = ctx.logManager().getLog(FetchAndAdd.class);
_mgr = mgr;

View File

@@ -306,8 +306,8 @@ public class I2PSnarkServlet extends BasicServlet {
String jsPfx = _context.isRouterContext() ? "" : ".resources";
String downMsg = _context.isRouterContext() ? _t("Router is down") : _t("I2PSnark has stopped");
// fallback to metarefresh when javascript is disabled
out.write("<noscript><meta http-equiv=\"refresh\" content=\"" + delay + ";" + _contextPath + "/" + peerString + "\"></noscript>\n");
out.write("<script src=\"" + jsPfx + "/js/ajax.js\" type=\"text/javascript\"></script>\n" +
out.write("<noscript><meta http-equiv=\"refresh\" content=\"" + delay + ";" + _contextPath + "/" + peerString + "\"></noscript>\n" +
"<script src=\"" + jsPfx + "/js/ajax.js\" type=\"text/javascript\"></script>\n" +
"<script type=\"text/javascript\">\n" +
"var failMessage = \"<div class=\\\"routerdown\\\"><b>" + downMsg + "<\\/b><\\/div>\";\n" +
"function requestAjax1() { ajax(\"" + _contextPath + "/.ajax/xhr1.html" +
@@ -350,10 +350,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(_contextName);
out.write("</a>\n");
sortedTrackers = _manager.getSortedTrackers();
if (_context.isRouterContext()) {
//out.write("<a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkNav nav_forum\" target=\"_blank\">");
//out.write(_t("Forum"));
//out.write("</a>\n");
if (_context.isRouterContext() && _manager.hasModifiedTrackers()) {
for (Tracker t : sortedTrackers) {
if (t.baseURL == null || !t.baseURL.startsWith("http"))
continue;
@@ -420,8 +417,8 @@ public class I2PSnarkServlet extends BasicServlet {
private void writeMessages(PrintWriter out, boolean isConfigure, String peerString) throws IOException {
List<UIMessages.Message> msgs = _manager.getMessages();
if (!msgs.isEmpty()) {
out.write("\n<div class=\"snarkMessages\" tabindex=\"0\">");
out.write("<a id=\"closeLog\" href=\"" + _contextPath + '/');
out.write("\n<div class=\"snarkMessages\" tabindex=\"0\">" +
"<a id=\"closeLog\" href=\"" + _contextPath + '/');
if (isConfigure)
out.write("configure");
if (peerString.length() > 0)
@@ -482,7 +479,7 @@ public class I2PSnarkServlet extends BasicServlet {
String currentSort = req.getParameter("sort");
boolean showSort = total > 1;
out.write("<tr><th class=\"snarkGraphicStatus\">");
String sort = ("2".equals(currentSort)) ? "-2" : "2";
String sort = ("-2".equals(currentSort)) ? "2" : "-2";
if (showSort) {
out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
out.write("\">");
@@ -495,23 +492,33 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("</a>");
out.write("</th>\n<th class=\"snarkTorrentStatus\">");
if (_manager.util().connected() && !snarks.isEmpty()) {
out.write(" <a href=\"" + _contextPath + '/');
if (peerParam != null) {
// disable peer view
out.write(getQueryString(req, "", null, null));
out.write("\">");
tx = _t("Hide Peers");
out.write(toThemeImg("hidepeers", tx, tx));
} else {
// enable peer view
out.write(getQueryString(req, "1", null, null));
out.write("\">");
tx = _t("Show Peers");
out.write(toThemeImg("showpeers", tx, tx));
boolean hasPeers = false;
int end = Math.min(start + pageSize, snarks.size());
for (int i = start; i < end; i++) {
if (snarks.get(i).getPeerCount() > 0) {
hasPeers = true;
break;
}
}
if (hasPeers) {
out.write(" <a href=\"" + _contextPath + '/');
if (peerParam != null) {
// disable peer view
out.write(getQueryString(req, "", null, null));
out.write("\">");
tx = _t("Hide Peers");
out.write(toThemeImg("hidepeers", tx, tx));
} else {
// enable peer view
out.write(getQueryString(req, "1", null, null));
out.write("\">");
tx = _t("Show Peers");
out.write(toThemeImg("showpeers", tx, tx));
}
out.write("</a>\n");
}
out.write("</a>\n");
}
out.write("</th>\n<th colspan=\"2\" align=\"left\">");
out.write("</th>\n<th colspan=\"3\" align=\"left\">");
// cycle through sort by name or type
boolean isTypeSort = false;
if (showSort) {
@@ -689,8 +696,8 @@ public class I2PSnarkServlet extends BasicServlet {
} else {
out.write("&nbsp;");
}
out.write("</th></tr>\n");
out.write("</thead>\n");
out.write("</th></tr>\n" +
"</thead>\n");
String uri = _contextPath + '/';
boolean showDebug = "2".equals(peerParam);
@@ -703,7 +710,7 @@ public class I2PSnarkServlet extends BasicServlet {
if (total == 0) {
out.write("<tr class=\"snarkTorrentNoneLoaded\">" +
"<td colspan=\"11\">");
"<td colspan=\"12\">");
synchronized(this) {
File dd = _resourceBase;
if (!dd.exists() && !dd.mkdirs()) {
@@ -721,7 +728,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("</td></tr>\n");
} else /** if (snarks.size() > 1) */ {
out.write("<tfoot><tr>\n" +
" <th id=\"snarkTorrentTotals\" align=\"left\" colspan=\"6\">");
" <th id=\"snarkTorrentTotals\" align=\"left\" colspan=\"7\">");
out.write("<span id=\"totals\">");
out.write(_t("Totals"));
out.write(":&nbsp;");
@@ -766,10 +773,10 @@ public class I2PSnarkServlet extends BasicServlet {
// TODO javascript handler to remember checkbox status for debug panel visibility (otherwise resets with ajax/meta refresh)
if (dht != null) {
if (showDebug) {
out.write("</tr>\n<tr class=\"dhtDebug\">");
out.write("<th colspan=\"11\">");
out.write("<div id=\"dhtDebugPanel\">");
out.write("<input class=\"toggle_input\" id=\"toggle_debug\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_debug\">");
out.write("</tr>\n<tr class=\"dhtDebug\">" +
"<th colspan=\"12\">" +
"<div id=\"dhtDebugPanel\">" +
"<input class=\"toggle_input\" id=\"toggle_debug\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_debug\">");
out.write(toThemeImg("debug"));
out.write(' ');
out.write(_t("Dht Debug"));
@@ -1635,15 +1642,12 @@ public class I2PSnarkServlet extends BasicServlet {
if (remaining == 0) {
img = "seeding";
txt = _t("Seeding");
tooltip = _t("Seeding to {0} of {1} peers in swarm", curPeers, knownPeers);
tooltip = ngettext("Seeding to {0} peer", "Seeding to {0} peers", knownPeers);
} else {
// partial
img = "complete";
txt = _t("Complete");
tooltip = txt;
if (curPeers > 0) {
tooltip = txt + " (" + _t("Seeding to {0} of {1} peers in swarm", curPeers, knownPeers) + ")";
}
}
if (curPeers > 0 && !showPeers) {
statusString = toThemeImg(img, "", tooltip) + "</td>" +
@@ -1669,12 +1673,12 @@ public class I2PSnarkServlet extends BasicServlet {
curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
} else if (isRunning && curPeers > 0 && downBps > 0) {
statusString = toThemeImg("downloading", "", _t("OK") + " (" + _t("Downloading from {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" +
statusString = toThemeImg("downloading", "", _t("OK") + ", " + ngettext("Downloading from {0} peer", "Downloading from {0} peers", curPeers)) + "</td>" +
"<td class=\"snarkTorrentStatus\"><b>" + _t("OK") +
":</b> " + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers);
} else if (isRunning && curPeers > 0 && !showPeers) {
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + _t("Connected to {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" +
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + ngettext("Connected to {0} peer", "Connected to {0} peers", curPeers)) + "</td>" +
"<td class=\"snarkTorrentStatus\"><b>" + _t("Stalled") +
":</b> <a href=\"" + uri + getQueryString(req, b64, null, null) + '#' + b64Short + "\">" +
curPeers + thinsp(noThinsp) +
@@ -1697,12 +1701,12 @@ public class I2PSnarkServlet extends BasicServlet {
}
}
out.write("<tr class=\"" + rowClass + "\" id=\"" + b64Short + "\">");
out.write("<td class=\"snarkGraphicStatus\" align=\"center\">");
out.write(statusString + "</td>\n\t");
out.write("<tr class=\"" + rowClass + "\" id=\"" + b64Short + "\">" +
"<td class=\"snarkGraphicStatus\" align=\"center\">");
out.write(statusString);
// (i) icon column
out.write("<td class=\"snarkTrackerDetails\">");
out.write("</td>\n<td class=\"snarkTrackerDetails\">");
if (isValid) {
String announce = meta.getAnnounce();
if (announce == null)
@@ -1743,6 +1747,21 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(toImg(icon));
}
// Comment icon column
out.write("</td>\n<td class=\"snarkCommentDetails\">");
if (isValid) {
CommentSet comments = snark.getComments();
if (comments != null && !comments.isEmpty()) {
StringBuilder buf = new StringBuilder(128);
buf.append("<a href=\"").append(encodedBaseName)
.append("/#snarkCommentSection\" title=\"").append(_t("Comments"))
.append("\">");
toThemeImg(buf, "comment", "", "");
buf.append("</a>");
out.write(buf.toString());
}
}
// Torrent name column
out.write("</td><td class=\"snarkTorrentName\">");
// No need for javascript here.. css now handles this
@@ -1776,9 +1795,9 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded\">");
if (remaining > 0) {
long percent = 100 * (total - remaining) / total;
out.write("<div class=\"percentBarOuter\">");
out.write("<div class=\"percentBarInner\" style=\"width: " + percent + "%;\">");
out.write("<div class=\"percentBarText\" tabindex=\"0\" title=\"");
out.write("<div class=\"percentBarOuter\">" +
"<div class=\"percentBarInner\" style=\"width: " + percent + "%;\">" +
"<div class=\"percentBarText\" tabindex=\"0\" title=\"");
out.write(percent + "% " + _t("complete") + "; " + formatSize(remaining) + ' ' + _t("remaining"));
out.write("\">");
out.write(formatSize(total-remaining) + thinsp(noThinsp) + formatSize(total));
@@ -1809,16 +1828,16 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(formatSize(uploaded));
}
}
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if (isRunning && needed > 0)
out.write("</td>\n\t" +
"<td align=\"right\" class=\"snarkTorrentRateDown\">");
if (isRunning && needed > 0 && (downBps > 0 || curPeers > 0))
out.write(formatSizeDec(downBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if (isRunning && isValid)
out.write("</td>\n\t" +
"<td align=\"right\" class=\"snarkTorrentRateUp\">");
if (isRunning && isValid && (upBps > 0 || curPeers > 0))
out.write(formatSizeDec(upBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"center\" class=\"snarkTorrentAction\">");
out.write("</td>\n\t" +
"<td align=\"center\" class=\"snarkTorrentAction\">");
if (snark.isChecking()) {
// show no buttons
} else if (isRunning) {
@@ -1882,15 +1901,15 @@ public class I2PSnarkServlet extends BasicServlet {
getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
out.write(_t("Delete the .torrent file and the associated data file(s)"));
out.write(_t("Delete the .torrent file and the associated data files"));
out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
// Single quotes in translate strings with parameters must be doubled.
// Then the remaining single quote must be escaped
out.write(_t("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?",
escapeJSString(fullBasename)));
out.write("')) { return false; }\"");
out.write(" src=\"" + _imgPath + "delete.png\" alt=\"");
out.write("')) { return false; }\"" +
" src=\"" + _imgPath + "delete.png\" alt=\"");
out.write(_t("Delete"));
out.write("\">");
if (isDegraded)
@@ -1908,7 +1927,7 @@ public class I2PSnarkServlet extends BasicServlet {
continue;
out.write("<tr class=\"peerinfo " + rowClass + "\"><td class=\"snarkGraphicStatus\" title=\"");
out.write(_t("Peer attached to swarm"));
out.write("\"></td><td colspan=\"4\">");
out.write("\"></td><td colspan=\"5\">");
PeerID pid = peer.getPeerID();
String ch = pid != null ? pid.toString().substring(0, 4) : "????";
String client;
@@ -1939,10 +1958,10 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("\">" + peer.toString().substring(5, 9)+ "</tt>");
if (showDebug)
out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s");
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentETA\">");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded\">");
out.write("</td>\n\t" +
"<td class=\"snarkTorrentETA\">" +
"</td>\n\t" +
"<td align=\"right\" class=\"snarkTorrentDownloaded\">");
float pct;
if (isValid) {
pct = (float) (100.0 * peer.completed() / meta.getPieces());
@@ -1952,20 +1971,20 @@ public class I2PSnarkServlet extends BasicServlet {
String ps = String.valueOf(pct);
if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write("<div class=\"percentBarOuter\">");
out.write("<div class=\"percentBarInner\" style=\"width:" + ps + "%;\">");
out.write("<div class=\"percentBarText\" tabindex=\"0\">" + ps + "%</div>");
out.write("</div></div>");
out.write("<div class=\"percentBarOuter\">" +
"<div class=\"percentBarInner\" style=\"width:" + ps + "%;\">" +
"<div class=\"percentBarText\" tabindex=\"0\">" + ps + "%</div>" +
"</div></div>");
}
} else {
pct = (float) 101.0;
// until we get the metainfo we don't know how many pieces there are
//out.write("??");
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentUploaded\">");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
out.write("</td>\n\t" +
"<td class=\"snarkTorrentUploaded\">" +
"</td>\n\t" +
"<td align=\"right\" class=\"snarkTorrentRateDown\">");
if (needed > 0) {
if (peer.isInteresting() && !peer.isChoked()) {
out.write("<span class=\"unchoked\">");
@@ -2002,11 +2021,11 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(formatSizeDec(peer.getUploadRate()) + "ps</span>");
}
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentAction\">");
out.write("</td></tr>\n\t");
out.write("</td>\n\t" +
"<td class=\"snarkTorrentAction\">" +
"</td></tr>\n\t");
if (showDebug)
out.write("<tr class=\"debuginfo " + rowClass + "\"><td class=\"snarkGraphicStatus\"></td><td colspan=\"10\">" + peer.getSocket() + "</td></tr>");
out.write("<tr class=\"debuginfo " + rowClass + "\"><td class=\"snarkGraphicStatus\"></td><td colspan=\"11\">" + peer.getSocket() + "</td></tr>");
}
}
}
@@ -2196,12 +2215,12 @@ public class I2PSnarkServlet extends BasicServlet {
//String newFile = req.getParameter("newFile");
//if ( (newFile == null) || (newFile.trim().length() <= 0) ) newFile = "";
out.write("<div class=\"snarkNewTorrent\">\n");
out.write("<div class=\"snarkNewTorrent\">\n" +
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
out.write("<form action=\"_post\" method=\"POST\">\n");
"<form action=\"_post\" method=\"POST\">\n");
writeHiddenInputs(out, req, "Add");
out.write("<div class=\"addtorrentsection\">");
out.write("<input class=\"toggle_input\" id=\"toggle_addtorrent\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_addtorrent\">");
out.write("<div class=\"addtorrentsection\">" +
"<input class=\"toggle_input\" id=\"toggle_addtorrent\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_addtorrent\">");
out.write(toThemeImg("add"));
out.write(' ');
out.write(_t("Add Torrent"));
@@ -2209,8 +2228,8 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("<hr>\n<table border=\"0\"><tr><td>");
out.write(_t("From URL"));
out.write(":<td><input type=\"text\" name=\"nofilter_newURL\" size=\"85\" value=\"" + newURL + "\" spellcheck=\"false\"");
out.write(" title=\"");
out.write(":<td><input type=\"text\" name=\"nofilter_newURL\" size=\"85\" value=\"" + newURL + "\" spellcheck=\"false\"" +
" title=\"");
out.write(_t("Enter the torrent file download URL (I2P only), magnet link, maggot link, or info hash"));
out.write("\">\n");
// not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve)
@@ -2221,8 +2240,8 @@ public class I2PSnarkServlet extends BasicServlet {
"<tr><td>");
out.write(_t("Data dir"));
out.write(":<td><input type=\"text\" name=\"nofilter_newDir\" size=\"85\" value=\"\" spellcheck=\"false\"");
out.write(" title=\"");
out.write(":<td><input type=\"text\" name=\"nofilter_newDir\" size=\"85\" value=\"\" spellcheck=\"false\"" +
" title=\"");
out.write(_t("Enter the directory to save the data in (default {0})", _manager.getDataDir().getAbsolutePath()));
out.write("\"></td></tr>\n");
@@ -2230,14 +2249,14 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(_t("You can also copy .torrent files to: {0}.", "<code>" + _manager.getDataDir().getAbsolutePath() + "</code>"));
out.write("\n");
out.write(_t("Removing a .torrent will cause it to stop."));
out.write("<br></span></table>\n");
out.write("</div></form></div>");
out.write("<br></span></table>\n" +
"</div></form></div>");
}
private void writeSeedForm(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers) throws IOException {
out.write("<a name=\"add\"></a><div class=\"newtorrentsection\"><div class=\"snarkNewTorrent\">\n");
out.write("<a name=\"add\"></a><div class=\"newtorrentsection\"><div class=\"snarkNewTorrent\">\n" +
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
out.write("<form action=\"_post\" method=\"POST\">\n");
"<form action=\"_post\" method=\"POST\">\n");
writeHiddenInputs(out, req, "Create");
out.write("<input class=\"toggle_input\" id=\"toggle_createtorrent\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_createtorrent\">");
out.write(toThemeImg("create"));
@@ -2253,8 +2272,8 @@ public class I2PSnarkServlet extends BasicServlet {
_manager.getDataDir().getAbsolutePath() + File.separatorChar));
out.write("\" > <input type=\"submit\" class=\"create\" value=\"");
out.write(_t("Create torrent"));
out.write("\" name=\"foo\" >");
out.write("<tr><td>\n");
out.write("\" name=\"foo\" >" +
"<tr><td>\n");
out.write(_t("Trackers"));
out.write(":<td><table id=\"trackerselect\"><tr><td>Name</td><td align=\"center\">");
out.write(_t("Primary"));
@@ -2492,7 +2511,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(":<td colspan=\"2\"><input type=\"text\" name=\"upLimit\" class=\"r\" value=\""
+ _manager.util().getMaxUploaders() + "\" size=\"4\" maxlength=\"3\""
+ " title=\"");
out.write(_t("Maximum number of peers to upload to"));
out.write(_t("Maximum number of peers for uploading"));
out.write("\"> ");
out.write(_t("peers"));
out.write("\n" +
@@ -2517,7 +2536,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(":</label><td colspan=\"2\"><input type=\"checkbox\" class=\"optbox\" name=\"useOpenTrackers\" id=\"useOpenTrackers\" value=\"true\" "
+ (useOpenTrackers ? "checked " : "")
+ "title=\"");
out.write(_t("Announce torrents to open trackers as well as tracker(s) listed in the torrent file"));
out.write(_t("Announce torrents to open trackers as well as trackers listed in the torrent file"));
out.write("\" ></td></tr>\n" +
"<tr><td><label for=\"useDHT\">");
@@ -2546,8 +2565,8 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(_t("Comment Author"));
out.write(":</td><td colspan=\"2\"><input type=\"text\" name=\"nofilter_commentsName\" spellcheck=\"false\" value=\""
+ DataHelper.escapeHTML(_manager.util().getCommentsName()) + "\" size=\"32\" maxlength=\"32\" title=\"");
out.write(_t("Set the author name for your comments and ratings"));
out.write("\" ></td></tr>\n");
out.write(_t("Set the author name for your comments and ratings"));
out.write("\" ></td></tr>\n");
// "<tr><td>");
//out.write(_t("Open tracker announce URLs"));
@@ -2912,7 +2931,8 @@ public class I2PSnarkServlet extends BasicServlet {
if (val != null) {
String nonce = val[0];
if (String.valueOf(_nonce).equals(nonce)) {
if (postParams.get("savepri") != null) {
if (postParams.get("savepri") != null ||
postParams.get("setInOrderEnabled") != null) {
savePriorities(snark, postParams);
} else if (postParams.get("addComment") != null) {
saveComments(snark, postParams);
@@ -2955,7 +2975,8 @@ public class I2PSnarkServlet extends BasicServlet {
}
boolean showStopStart = snark != null;
boolean showPriority = snark != null && snark.getStorage() != null && !snark.getStorage().complete() &&
Storage storage = snark != null ? snark.getStorage() : null;
boolean showPriority = storage != null && !storage.complete() &&
r.isDirectory();
StringBuilder buf=new StringBuilder(4096);
@@ -2969,15 +2990,15 @@ public class I2PSnarkServlet extends BasicServlet {
buf.append(title);
buf.append("</title>\n").append(HEADER_A).append(_themePath).append(HEADER_B)
// hide javascript-dependent buttons when js is unavailable
.append("<noscript><style type=\"text/css\">.script {display: none;}</style></noscript>")
.append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n");
.append("<noscript><style type=\"text/css\">.script {display: none;}</style></noscript>" +
"<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n");
if (showPriority)
buf.append("<script src=\"").append(_contextPath).append(WARBASE + "js/folder.js\" type=\"text/javascript\"></script>\n");
buf.append("</head><body");
if (showPriority)
buf.append(" onload=\"setupbuttons()\"");
buf.append(">\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"");
buf.append(" class=\"snarkNav nav_main\">");
buf.append(">\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"" +
" class=\"snarkNav nav_main\">");
if (_contextName.equals(DEFAULT_NAME))
buf.append(_t("I2PSnark"));
else
@@ -2992,8 +3013,8 @@ public class I2PSnarkServlet extends BasicServlet {
final boolean esc = ec && _manager.getSavedCommentsEnabled(snark); // per-torrent setting
final boolean includeForm = showStopStart || showPriority || er || ec;
if (includeForm) {
buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
buf.append("<input type=\"hidden\" name=\"nonce\" value=\"").append(_nonce).append("\" >\n");
buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n" +
"<input type=\"hidden\" name=\"nonce\" value=\"").append(_nonce).append("\" >\n");
if (sortParam != null) {
buf.append("<input type=\"hidden\" name=\"sort\" value=\"")
.append(DataHelper.stripHTML(sortParam)).append("\" >\n");
@@ -3001,8 +3022,8 @@ public class I2PSnarkServlet extends BasicServlet {
}
if (snark != null) {
// first table - torrent info
buf.append("<table class=\"snarkTorrentInfo\">\n");
buf.append("<tr><th></th><th><b>")
buf.append("<table class=\"snarkTorrentInfo\">\n" +
"<tr><th></th><th><b>")
.append(_t("Torrent"))
.append(":</b> ")
.append(DataHelper.escapeHTML(snark.getBaseName()))
@@ -3017,13 +3038,13 @@ public class I2PSnarkServlet extends BasicServlet {
.append(":</b> <a href=\"").append(_contextPath).append('/').append(baseName).append("\">")
.append(DataHelper.escapeHTML(fullPath))
.append("</a></td></tr>\n");
if (snark.getStorage() != null) {
if (storage != null) {
buf.append("<tr><td>");
toThemeImg(buf, "file");
buf.append("</td><td><b>")
.append(_t("Data location"))
.append(":</b> ")
.append(DataHelper.escapeHTML(snark.getStorage().getBase().getPath()))
.append(DataHelper.escapeHTML(storage.getBase().getPath()))
.append("</td></tr>\n");
}
String hex = I2PSnarkUtil.toHex(snark.getInfoHash());
@@ -3261,11 +3282,29 @@ public class I2PSnarkServlet extends BasicServlet {
.append("\">\n");
else
buf.append("\" class=\"reload\" title=\"")
.append(_t("Check integrity of the downloaded file(s)"))
.append(_t("Check integrity of the downloaded files"))
.append("\">\n");
}
boolean showInOrder = storage != null && !storage.complete() &&
meta != null;
if (showInOrder) {
buf.append("</td></tr>\n" +
"<tr id=\"torrentOrderControl\"><td colspan=\"2\">");
String txt = (meta.getFiles() != null && meta.getFiles().size() > 1) ?
_t("Download files in order") :
_t("Download pieces in order");
buf.append(txt);
buf.append(":<input type=\"checkbox\" class=\"optbox\" name=\"enableInOrder\" id=\"enableInOrder\" ");
if (storage.getInOrder())
buf.append("checked=\"checked\"");
buf.append(">" +
"<input type=\"submit\" name=\"setInOrderEnabled\" value=\"");
buf.append(_t("Save Preference"));
buf.append("\" class=\"accept\">");
}
buf.append("</td></tr>\n");
}
} else {
// snark == null
// shouldn't happen
@@ -3304,7 +3343,6 @@ public class I2PSnarkServlet extends BasicServlet {
return buf.toString();
}
Storage storage = snark != null ? snark.getStorage() : null;
List<Sorters.FileAndIndex> fileList = new ArrayList<Sorters.FileAndIndex>(ls.length);
// precompute remaining for all files for efficiency
long[] remainingArray = (storage != null) ? storage.remaining() : null;
@@ -3324,9 +3362,9 @@ public class I2PSnarkServlet extends BasicServlet {
}
// second table - dir info
buf.append("<table class=\"snarkDirInfo\"><thead>\n");
buf.append("<tr>\n")
.append("<th colspan=2>");
buf.append("<table class=\"snarkDirInfo\"><thead>\n" +
"<tr>\n" +
"<th colspan=2>");
String tx = _t("Directory");
// cycle through sort by name or type
String sort;
@@ -3391,8 +3429,8 @@ public class I2PSnarkServlet extends BasicServlet {
if (showSort)
buf.append("</a>");
}
buf.append("</th>\n</tr>\n</thead>\n");
buf.append("<tr><td colspan=\"" + (showPriority ? '5' : '4') + "\" class=\"ParentDir\"><A HREF=\"");
buf.append("</th>\n</tr>\n</thead>\n" +
"<tr><td colspan=\"" + (showPriority ? '5' : '4') + "\" class=\"ParentDir\"><A HREF=\"");
URIUtil.encodePath(buf, addPaths(decodedBase,"../"));
buf.append("\">");
toThemeImg(buf, "up");
@@ -3405,6 +3443,7 @@ public class I2PSnarkServlet extends BasicServlet {
// DateFormat.MEDIUM);
boolean showSaveButton = false;
boolean rowEven = true;
boolean inOrder = storage != null && storage.getInOrder();
for (Sorters.FileAndIndex fai : fileList)
{
//String encoded = encodePath(ls[i].getName());
@@ -3428,7 +3467,7 @@ public class I2PSnarkServlet extends BasicServlet {
complete = true;
//status = toImg("tick") + ' ' + _t("Directory");
} else {
if (snark == null || snark.getStorage() == null) {
if (storage == null) {
// Assume complete, perhaps he removed a completed torrent but kept a bookmark
complete = true;
status = toImg("cancel") + ' ' + _t("Torrent not found?");
@@ -3508,22 +3547,24 @@ public class I2PSnarkServlet extends BasicServlet {
if (showPriority) {
buf.append("<td class=\"priority\">");
if ((!complete) && (!item.isDirectory())) {
buf.append("<label class=\"priorityHigh\" title=\"").append(_t("Download file at high priority")).append("\">")
.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
if (priority > 0)
buf.append("checked=\"checked\"");
buf.append('>')
.append(_t("High")).append("</label>");
if (!inOrder) {
buf.append("<label class=\"priorityHigh\" title=\"").append(_t("Download file at high priority")).append("\">" +
"\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
if (priority > 0)
buf.append("checked=\"checked\"");
buf.append('>')
.append(_t("High")).append("</label>");
}
buf.append("<label class=\"priorityNormal\" title=\"").append(_t("Download file at normal priority")).append("\">")
.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
if (priority == 0)
buf.append("<label class=\"priorityNormal\" title=\"").append(_t("Download file at normal priority")).append("\">" +
"\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
if (priority == 0 || (inOrder && priority >= 0))
buf.append("checked=\"checked\"");
buf.append('>')
.append(_t("Normal")).append("</label>");
buf.append("<label class=\"prioritySkip\" title=\"").append(_t("Do not download this file")).append("\">")
.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
buf.append("<label class=\"prioritySkip\" title=\"").append(_t("Do not download this file")).append("\">" +
"\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
if (priority < 0)
buf.append("checked=\"checked\"");
buf.append('>')
@@ -3536,9 +3577,12 @@ public class I2PSnarkServlet extends BasicServlet {
}
if (showSaveButton) {
buf.append("<thead><tr id=\"setPriority\"><th class=\"headerpriority\" colspan=\"5\">" +
"<span class=\"script\"><a class=\"control\" id=\"setallhigh\" href=\"javascript:void(null);\" onclick=\"setallhigh();\">")
.append(toImg("clock_red")).append(_t("Set all high")).append("</a>\n" +
"<a class=\"control\" id=\"setallnorm\" href=\"javascript:void(null);\" onclick=\"setallnorm();\">")
"<span class=\"script\">");
if (!inOrder) {
buf.append("<a class=\"control\" id=\"setallhigh\" href=\"javascript:void(null);\" onclick=\"setallhigh();\">")
.append(toImg("clock_red")).append(_t("Set all high")).append("</a>\n");
}
buf.append("<a class=\"control\" id=\"setallnorm\" href=\"javascript:void(null);\" onclick=\"setallnorm();\">")
.append(toImg("clock")).append(_t("Set all normal")).append("</a>\n" +
"<a class=\"control\" id=\"setallskip\" href=\"javascript:void(null);\" onclick=\"setallskip();\">")
.append(toImg("cancel")).append(_t("Skip all")).append("</a></span>\n" +
@@ -3907,7 +3951,9 @@ public class I2PSnarkServlet extends BasicServlet {
} catch (Throwable t) { t.printStackTrace(); }
}
}
snark.updatePiecePriorities();
if (postParams.get("setInOrderEnabled") != null)
storage.setInOrder(postParams.get("enableInOrder") != null);
snark.updatePiecePriorities();
_manager.saveTorrentStatus(snark);
}

View File

@@ -128,6 +128,7 @@ class Sorters {
private static class TorrentNameComparator implements Comparator<Snark>, Serializable {
private final Pattern _p;
private static final Collator _c = Collator.getInstance();
/** @param lang may be null */
private TorrentNameComparator(String lang) {
@@ -155,7 +156,7 @@ class Sorters {
if (m.matches())
rs = rs.substring(m.group(1).length());
}
return Collator.getInstance().compare(ls, rs);
return _c.compare(ls, rs);
}
}
@@ -207,10 +208,10 @@ class Sorters {
long remaining = snark.getRemainingLength();
if (snark.isStopped()) {
if (remaining < 0)
return 0;
return 10;
if (remaining > 0)
return 5;
return 10;
return 0;
}
if (snark.isStarting())
return 15;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More