@@ -47,37 +47,21 @@ public class GeoIpService {
4747
4848 private static final String DATABASE_NAME = "GeoLite2-Country" ;
4949 private static final String DATABASE_FILE = DATABASE_NAME + ".mmdb" ;
50- private static final String DATABASE_TMP_FILE = DATABASE_NAME + ".mmdb.tmp" ;
51-
52- private static final String ARCHIVE_FILE = DATABASE_NAME + ".mmdb.gz" ;
53-
54- private static final String ARCHIVE_URL =
55- "https://updates.maxmind.com/geoip/databases/" + DATABASE_NAME + "/update" ;
56-
57- private static final int UPDATE_INTERVAL_DAYS = 30 ;
58-
5950 private final ConsoleLogger logger = ConsoleLoggerFactory .get (GeoIpService .class );
6051 private final Path dataFile ;
61- private final BukkitService bukkitService ;
62- private final Settings settings ;
63-
6452 private GeoIp2Provider databaseReader ;
6553 private volatile boolean downloading ;
6654
6755 @ Inject
68- GeoIpService (@ DataFolder File dataFolder , BukkitService bukkitService , Settings settings ) {
69- this .bukkitService = bukkitService ;
56+ GeoIpService (@ DataFolder File dataFolder ) {
7057 this .dataFile = dataFolder .toPath ().resolve (DATABASE_FILE );
71- this .settings = settings ;
7258
7359 // Fires download of recent data or the initialization of the look up service
7460 isDataAvailable ();
7561 }
7662
7763 @ VisibleForTesting
78- GeoIpService (@ DataFolder File dataFolder , BukkitService bukkitService , Settings settings , GeoIp2Provider reader ) {
79- this .bukkitService = bukkitService ;
80- this .settings = settings ;
64+ GeoIpService (@ DataFolder File dataFolder , GeoIp2Provider reader ) {
8165 this .dataFile = dataFolder .toPath ().resolve (DATABASE_FILE );
8266
8367 this .databaseReader = reader ;
@@ -101,73 +85,19 @@ private synchronized boolean isDataAvailable() {
10185
10286 if (Files .exists (dataFile )) {
10387 try {
104- FileTime lastModifiedTime = Files .getLastModifiedTime (dataFile );
105- if (Duration .between (lastModifiedTime .toInstant (), Instant .now ()).toDays () <= UPDATE_INTERVAL_DAYS ) {
106- startReading ();
107-
108- // don't fire the update task - we are up to date
109- return true ;
110- } else {
111- logger .debug ("GEO IP database is older than " + UPDATE_INTERVAL_DAYS + " Days" );
112- }
88+ startReading ();
89+ // don't fire the update task - we are up to date
90+ return true ;
11391 } catch (IOException ioEx ) {
11492 logger .logException ("Failed to load GeoLiteAPI database" , ioEx );
11593 return false ;
11694 }
11795 }
118-
119- //set the downloading flag in order to fix race conditions outside
120- downloading = true ;
121-
12296 // File is outdated or doesn't exist - let's try to download the data file!
12397 // use bukkit's cached threads
124- bukkitService .runTaskAsynchronously (this ::updateDatabase );
12598 return false ;
12699 }
127100
128- /**
129- * Tries to update the database by downloading a new version from the website.
130- */
131- private void updateDatabase () {
132- logger .info ("Downloading GEO IP database, because the old database is older than "
133- + UPDATE_INTERVAL_DAYS + " days or doesn't exist" );
134-
135- Path downloadFile = null ;
136- Path tempFile = null ;
137- try {
138- // download database to temporarily location
139- downloadFile = Files .createTempFile (ARCHIVE_FILE , null );
140- tempFile = Files .createTempFile (DATABASE_TMP_FILE , null );
141- String expectedChecksum = downloadDatabaseArchive (downloadFile );
142- if (expectedChecksum == null ) {
143- logger .info ("There is no newer GEO IP database uploaded to MaxMind. Using the old one for now." );
144- startReading ();
145- return ;
146- }
147-
148- // tar extract database and copy to target destination
149- extractDatabase (downloadFile , tempFile );
150-
151- // MD5 checksum verification
152- verifyChecksum (Hashing .md5 (), tempFile , expectedChecksum );
153-
154- Files .copy (tempFile , dataFile , StandardCopyOption .REPLACE_EXISTING );
155-
156- //only set this value to false on success otherwise errors could lead to endless download triggers
157- logger .info ("Successfully downloaded new GEO IP database to " + dataFile );
158- startReading ();
159- } catch (IOException ioEx ) {
160- logger .logException ("Could not download GeoLiteAPI database" , ioEx );
161- } finally {
162- // clean up
163- if (downloadFile != null ) {
164- FileUtils .delete (downloadFile .toFile ());
165- }
166- if (tempFile != null ) {
167- FileUtils .delete (tempFile .toFile ());
168- }
169- }
170- }
171101
172102 private void startReading () throws IOException {
173103 databaseReader = new Reader (dataFile .toFile (), FileMode .MEMORY , new CHMCache ());
@@ -177,101 +107,6 @@ private void startReading() throws IOException {
177107 downloading = false ;
178108 }
179109
180- /**
181- * Downloads the archive to the destination file if it's newer than the locally version.
182- *
183- * @param lastModified modification timestamp of the already present file
184- * @param destination save file
185- * @return null if no updates were found, the MD5 hash of the downloaded archive if successful
186- * @throws IOException if failed during downloading and writing to destination file
187- */
188- private String downloadDatabaseArchive (Instant lastModified , Path destination ) throws IOException {
189- String clientId = settings .getProperty (ProtectionSettings .MAXMIND_API_CLIENT_ID );
190- String licenseKey = settings .getProperty (ProtectionSettings .MAXMIND_API_LICENSE_KEY );
191- if (clientId .isEmpty () || licenseKey .isEmpty ()) {
192- logger .warning ("No MaxMind credentials found in the configuration file!"
193- + " GeoIp protections will be disabled." );
194- return null ;
195- }
196-
197- HttpURLConnection connection = (HttpURLConnection ) new URL (ARCHIVE_URL ).openConnection ();
198- String basicAuth = "Basic " + new String (Base64 .getEncoder ().encode ((clientId + ":" + licenseKey ).getBytes ()));
199- connection .setRequestProperty ("Authorization" , basicAuth );
200-
201- if (lastModified != null ) {
202- // Only download if we actually need a newer version - this field is specified in GMT zone
203- ZonedDateTime zonedTime = lastModified .atZone (ZoneId .of ("GMT" ));
204- String timeFormat = DateTimeFormatter .RFC_1123_DATE_TIME .format (zonedTime );
205- connection .addRequestProperty ("If-Modified-Since" , timeFormat );
206- }
207-
208- if (connection .getResponseCode () == HttpURLConnection .HTTP_NOT_MODIFIED ) {
209- //we already have the newest version
210- connection .getInputStream ().close ();
211- return null ;
212- }
213-
214- String hash = connection .getHeaderField ("X-Database-MD5" );
215- String rawModifiedDate = connection .getHeaderField ("Last-Modified" );
216- Instant modifiedDate = Instant .from (DateTimeFormatter .RFC_1123_DATE_TIME .parse (rawModifiedDate ));
217- Files .copy (connection .getInputStream (), destination , StandardCopyOption .REPLACE_EXISTING );
218- Files .setLastModifiedTime (destination , FileTime .from (modifiedDate ));
219- return hash ;
220- }
221-
222- /**
223- * Downloads the archive to the destination file if it's newer than the locally version.
224- *
225- * @param destination save file
226- * @return null if no updates were found, the MD5 hash of the downloaded archive if successful
227- * @throws IOException if failed during downloading and writing to destination file
228- */
229- private String downloadDatabaseArchive (Path destination ) throws IOException {
230- Instant lastModified = null ;
231- if (Files .exists (dataFile )) {
232- lastModified = Files .getLastModifiedTime (dataFile ).toInstant ();
233- }
234-
235- return downloadDatabaseArchive (lastModified , destination );
236- }
237-
238- /**
239- * Verify if the expected checksum is equal to the checksum of the given file.
240- *
241- * @param function the checksum function like MD5, SHA256 used to generate the checksum from the file
242- * @param file the file we want to calculate the checksum from
243- * @param expectedChecksum the expected checksum
244- * @throws IOException on I/O error reading the file or the checksum verification failed
245- */
246- private void verifyChecksum (HashFunction function , Path file , String expectedChecksum ) throws IOException {
247- HashCode actualHash = function .hashBytes (Files .readAllBytes (file ));
248- HashCode expectedHash = HashCode .fromString (expectedChecksum );
249- if (!Objects .equals (actualHash , expectedHash )) {
250- throw new IOException ("GEO IP Checksum verification failed. "
251- + "Expected: " + expectedChecksum + "Actual:" + actualHash );
252- }
253- }
254-
255- /**
256- * Extract the database from gzipped data. Existing outputFile will be replaced if it already exists.
257- *
258- * @param inputFile gzipped database input file
259- * @param outputFile destination file for the database
260- * @throws IOException on I/O error reading the archive, or writing the output
261- */
262- private void extractDatabase (Path inputFile , Path outputFile ) throws IOException {
263- // .gz -> gzipped file
264- try (BufferedInputStream in = new BufferedInputStream (Files .newInputStream (inputFile ));
265- GZIPInputStream gzipIn = new GZIPInputStream (in )) {
266-
267- // found the database file and copy file
268- Files .copy (gzipIn , outputFile , StandardCopyOption .REPLACE_EXISTING );
269-
270- // update the last modification date to be same as in the archive
271- Files .setLastModifiedTime (outputFile , Files .getLastModifiedTime (inputFile ));
272- }
273- }
274-
275110 /**
276111 * Get the country code of the given IP address.
277112 *
0 commit comments