diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java index 966860b..9c497cd 100644 --- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java +++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/captcha/ImageCaptchaService.java @@ -3,6 +3,7 @@ */ package com.rogiel.httpchannel.captcha; +import java.net.MalformedURLException; import java.net.URL; /** @@ -17,8 +18,10 @@ public interface ImageCaptchaService extends * @param image * the image {@link URL} * @return a new captcha + * @throws MalformedURLException + * if any error occur while creating the Image {@link URL} */ - C create(String html); + C create(String html) throws MalformedURLException; /** * Tries to automatically resolve the captcha diff --git a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java index d70838b..90dbdaf 100644 --- a/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java +++ b/httpchannel-api/src/main/java/com/rogiel/httpchannel/service/AbstractService.java @@ -43,7 +43,7 @@ public abstract class AbstractService implements Service { this.captchaResolver = captchaResolver; } - protected boolean resolveCaptcha(Captcha captcha) + protected void resolveCaptcha(Captcha captcha) throws UnresolvedCaptchaException { if (captchaResolver == null) throw new UnresolvedCaptchaException(); @@ -51,6 +51,5 @@ public abstract class AbstractService implements Service { throw new UnresolvedCaptchaException(); if (captcha.getAnswer() == null) throw new UnresolvedCaptchaException(); - return true; } } diff --git a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaService.java b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaService.java new file mode 100644 index 0000000..5716ebf --- /dev/null +++ b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaService.java @@ -0,0 +1,36 @@ +/** + * + */ +package com.rogiel.httpchannel.captcha.impl; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.regex.Pattern; + +import com.rogiel.httpchannel.util.PatternUtils; + +/** + * @author Rogiel + */ +public class AjaxReCaptchaService extends BaseReCaptchaService { + private static final Pattern CAPTCHA_URL_PATTERN = Pattern + .compile("Recaptcha\\.create\\(\"([0-9A-z|_|\\-]*)\", "); + private static final String BASE_URL = "http://www.google.com/recaptcha/api/challenge?ajax=1&k="; + + @Override + public ReCaptcha create(String content) throws MalformedURLException { + final String siteID = PatternUtils + .find(CAPTCHA_URL_PATTERN, content, 1); + try { + return super.create(get(BASE_URL + siteID).asString()); + } catch (IOException e) { + return null; + } + } + + @Override + public boolean resolve(ReCaptcha captcha) { + // not supported! + return false; + } +} diff --git a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/BaseReCaptchaService.java b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/BaseReCaptchaService.java new file mode 100644 index 0000000..a90081a --- /dev/null +++ b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/BaseReCaptchaService.java @@ -0,0 +1,34 @@ +/** + * + */ +package com.rogiel.httpchannel.captcha.impl; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.regex.Pattern; + +import com.rogiel.httpchannel.captcha.AbstractImageCaptchaService; +import com.rogiel.httpchannel.util.PatternUtils; + +/** + * @author Rogiel + * + */ +public class BaseReCaptchaService extends + AbstractImageCaptchaService { + private static final Pattern CAPTCHA_IMAGE_PATTERN = Pattern + .compile("challenge : '(.*)'"); + private static final String BASE_URL = "http://www.google.com/recaptcha/api/image?c="; + + @Override + public ReCaptcha create(String content) throws MalformedURLException { + final String id = PatternUtils.find(CAPTCHA_IMAGE_PATTERN, content, 1); + return new ReCaptcha(new URL(BASE_URL + id), id); + } + + @Override + public boolean resolve(ReCaptcha captcha) { + // not supported! + return false; + } +} diff --git a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/EmbeddedReCaptchaService.java b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/EmbeddedReCaptchaService.java new file mode 100644 index 0000000..ae320e3 --- /dev/null +++ b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/EmbeddedReCaptchaService.java @@ -0,0 +1,41 @@ +/** + * + */ +package com.rogiel.httpchannel.captcha.impl; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.regex.Pattern; + +import com.rogiel.httpchannel.util.htmlparser.HTMLPage; + +/** + * @author Rogiel + * + */ +public class EmbeddedReCaptchaService extends BaseReCaptchaService { + private static final Pattern CAPTCHA_URL_PATTERN = Pattern + .compile("http://www\\.google\\.com/recaptcha/api/challenge\\?k=([0-9A-z|\\-]*)(&(.*))?"); + + @Override + public ReCaptcha create(String content) throws MalformedURLException { + try { + return create(HTMLPage.parse(content)); + } catch (IOException e) { + return null; + } + } + + public ReCaptcha create(HTMLPage page) throws IOException { + final String url = page.findScriptSrc(CAPTCHA_URL_PATTERN); + if (url == null) + return null; + return super.create(get(url).asString()); + } + + @Override + public boolean resolve(ReCaptcha captcha) { + // not supported! + return false; + } +} diff --git a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/ReCaptchaService.java b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/ReCaptchaService.java deleted file mode 100644 index a2ca273..0000000 --- a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/main/java/com/rogiel/httpchannel/captcha/impl/ReCaptchaService.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - */ -package com.rogiel.httpchannel.captcha.impl; - -import java.io.IOException; -import java.net.URL; -import java.util.regex.Pattern; - -import com.rogiel.httpchannel.captcha.AbstractImageCaptchaService; -import com.rogiel.httpchannel.util.PatternUtils; -import com.rogiel.httpchannel.util.htmlparser.HTMLPage; - -/** - * @author Rogiel - * - */ -public class ReCaptchaService extends AbstractImageCaptchaService { - // http://www.google.com/recaptcha/api/noscript?k=6LdRTL8SAAAAAE9UOdWZ4d0Ky-aeA7XfSqyWDM2m - private static final Pattern CAPTCHA_URL_PATTERN = Pattern - .compile("http://www\\.google\\.com/recaptcha/api/challenge\\?k=([0-9A-z|\\-]*)(&(.*))?"); - private static final Pattern CAPTCHA_IMAGE_PATTERN = Pattern - .compile("challenge : '(.*)'"); - private static final String BASE_URL = "http://www.google.com/recaptcha/api/image?c="; - - @Override - public ReCaptcha create(HTMLPage page) throws IOException { - final String url = page.findScriptSrc(CAPTCHA_URL_PATTERN); - - if (url == null) - return null; - final String captchaPage = get(url).asString(); - - final String id = PatternUtils.find(CAPTCHA_IMAGE_PATTERN, captchaPage, - 1); - return new ReCaptcha(new URL(BASE_URL + id), id); - } - - @Override - public boolean resolve(ReCaptcha captcha) { - // not supported! - return false; - } -} diff --git a/httpchannel-capcha/httpchannel-captcha-recaptcha/src/test/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaServiceTest.java b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/test/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaServiceTest.java new file mode 100644 index 0000000..81c0708 --- /dev/null +++ b/httpchannel-capcha/httpchannel-captcha-recaptcha/src/test/java/com/rogiel/httpchannel/captcha/impl/AjaxReCaptchaServiceTest.java @@ -0,0 +1,25 @@ +/** + * + */ +package com.rogiel.httpchannel.captcha.impl; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +/** + * @author Rogiel + * + */ +public class AjaxReCaptchaServiceTest { + @Test + public void test() throws MalformedURLException, IOException { + final String content = IOUtils.toString(new URL( + "http://www.uploadking.com/WM3PHD9JAY").openStream()); + final AjaxReCaptchaService ajax = new AjaxReCaptchaService(); + ajax.create(content); + } +} diff --git a/httpchannel-capcha/pom.xml b/httpchannel-capcha/pom.xml index 21a669d..1ed1a8f 100644 --- a/httpchannel-capcha/pom.xml +++ b/httpchannel-capcha/pom.xml @@ -1,16 +1,19 @@ - - 4.0.0 - - httpchannel - com.rogiel.httpchannel - 1.0.0 - .. - - httpchannel-capcha - HttpChannel/CaptchaService - This module provides implementations for captcha resolving - pom - - httpchannel-captcha-recaptcha - + + 4.0.0 + + httpchannel + com.rogiel.httpchannel + 1.0.0 + .. + + httpchannel-capcha + pom + + HttpChannel/CaptchaService + This module provides implementations for captcha resolving + + + httpchannel-captcha-recaptcha + \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-depositfiles/src/main/java/com/rogiel/httpchannel/service/impl/DepositFilesService.java b/httpchannel-service/httpchannel-service-depositfiles/src/main/java/com/rogiel/httpchannel/service/impl/DepositFilesService.java index 735c196..95a207f 100644 --- a/httpchannel-service/httpchannel-service-depositfiles/src/main/java/com/rogiel/httpchannel/service/impl/DepositFilesService.java +++ b/httpchannel-service/httpchannel-service-depositfiles/src/main/java/com/rogiel/httpchannel/service/impl/DepositFilesService.java @@ -5,8 +5,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.regex.Pattern; +import com.rogiel.httpchannel.captcha.impl.EmbeddedReCaptchaService; import com.rogiel.httpchannel.captcha.impl.ReCaptcha; -import com.rogiel.httpchannel.captcha.impl.ReCaptchaService; import com.rogiel.httpchannel.service.AbstractAuthenticator; import com.rogiel.httpchannel.service.AbstractHttpService; import com.rogiel.httpchannel.service.AbstractUploader; @@ -26,7 +26,6 @@ import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadCh import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration; import com.rogiel.httpchannel.service.config.NullUploaderConfiguration; import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException; -import com.rogiel.httpchannel.service.exception.UnresolvedCaptchaException; import com.rogiel.httpchannel.util.htmlparser.HTMLPage; /** @@ -51,7 +50,7 @@ public class DepositFilesService extends AbstractHttpService implements private static final Pattern VALID_LOGIN_REDIRECT = Pattern .compile("window.location.href"); - private final ReCaptchaService captchaService = new ReCaptchaService(); + private final EmbeddedReCaptchaService captchaService = new EmbeddedReCaptchaService(); @Override public ServiceID getID() { @@ -71,7 +70,7 @@ public class DepositFilesService extends AbstractHttpService implements @Override public Uploader getUploader(String filename, long filesize, NullUploaderConfiguration configuration) { - return new UploadKingUploader(filename, filesize, configuration); + return new UploaderImpl(filename, filesize, configuration); } @Override @@ -106,7 +105,7 @@ public class DepositFilesService extends AbstractHttpService implements @Override public Authenticator getAuthenticator( Credential credential, NullAuthenticatorConfiguration configuration) { - return new UploadKingAuthenticator(credential, configuration); + return new AuthenticatorImpl(credential, configuration); } @Override @@ -125,13 +124,13 @@ public class DepositFilesService extends AbstractHttpService implements return new CapabilityMatrix(); } - protected class UploadKingUploader extends + protected class UploaderImpl extends AbstractUploader implements Uploader, LinkedUploadChannelCloseCallback { private Future uploadFuture; - public UploadKingUploader(String filename, long filesize, + public UploaderImpl(String filename, long filesize, NullUploaderConfiguration configuration) { super(filename, filesize, configuration); } @@ -169,10 +168,10 @@ public class DepositFilesService extends AbstractHttpService implements } } - protected class UploadKingAuthenticator extends + protected class AuthenticatorImpl extends AbstractAuthenticator implements Authenticator { - public UploadKingAuthenticator(Credential credential, + public AuthenticatorImpl(Credential credential, NullAuthenticatorConfiguration configuration) { super(credential, configuration); } @@ -186,8 +185,7 @@ public class DepositFilesService extends AbstractHttpService implements final ReCaptcha captcha = captchaService.create(page); if (captcha != null) { - if (!resolveCaptcha(captcha)) - throw new UnresolvedCaptchaException(); + resolveCaptcha(captcha); page = post("http://depositfiles.com/login.php?return=%2F") .parameter("go", true) .parameter("login", credential.getUsername()) diff --git a/httpchannel-service/httpchannel-service-depositfiles/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service b/httpchannel-service/httpchannel-service-depositfiles/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service index 4013beb..000989d 100644 --- a/httpchannel-service/httpchannel-service-depositfiles/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service +++ b/httpchannel-service/httpchannel-service-depositfiles/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service @@ -1 +1 @@ -com.rogiel.httpchannel.service.impl.MultiUploadService \ No newline at end of file +com.rogiel.httpchannel.service.impl.DepositFilesService \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-hotfile/src/main/java/com/rogiel/httpchannel/service/impl/HotFileService.java b/httpchannel-service/httpchannel-service-hotfile/src/main/java/com/rogiel/httpchannel/service/impl/HotFileService.java index 34d3a20..f508da8 100644 --- a/httpchannel-service/httpchannel-service-hotfile/src/main/java/com/rogiel/httpchannel/service/impl/HotFileService.java +++ b/httpchannel-service/httpchannel-service-hotfile/src/main/java/com/rogiel/httpchannel/service/impl/HotFileService.java @@ -102,7 +102,7 @@ public class HotFileService extends AbstractHttpService implements Service, @Override public Uploader getUploader(String filename, long filesize, NullUploaderConfiguration configuration) { - return new HotFileUploader(filename, filesize, configuration); + return new UploaderImpl(filename, filesize, configuration); } @Override @@ -137,7 +137,7 @@ public class HotFileService extends AbstractHttpService implements Service, @Override public Downloader getDownloader(URL url, NullDownloaderConfiguration configuration) { - return new HotFileDownloader(url, configuration); + return new DownloaderImpl(url, configuration); } @Override @@ -164,7 +164,7 @@ public class HotFileService extends AbstractHttpService implements Service, @Override public Authenticator getAuthenticator( Credential credential, NullAuthenticatorConfiguration configuration) { - return new HotFileAuthenticator(credential, configuration); + return new AuthenticatorImpl(credential, configuration); } @Override @@ -183,13 +183,13 @@ public class HotFileService extends AbstractHttpService implements Service, return new CapabilityMatrix(); } - protected class HotFileUploader extends + protected class UploaderImpl extends AbstractUploader implements Uploader, LinkedUploadChannelCloseCallback { private Future uploadFuture; - public HotFileUploader(String filename, long filesize, + public UploaderImpl(String filename, long filesize, NullUploaderConfiguration configuration) { super(filename, filesize, configuration); } @@ -218,9 +218,9 @@ public class HotFileService extends AbstractHttpService implements Service, } } - protected class HotFileDownloader extends + protected class DownloaderImpl extends AbstractHttpDownloader { - public HotFileDownloader(URL url, + public DownloaderImpl(URL url, NullDownloaderConfiguration configuration) { super(url, configuration); } @@ -304,10 +304,10 @@ public class HotFileService extends AbstractHttpService implements Service, } } - protected class HotFileAuthenticator extends + protected class AuthenticatorImpl extends AbstractAuthenticator implements Authenticator { - public HotFileAuthenticator(Credential credential, + public AuthenticatorImpl(Credential credential, NullAuthenticatorConfiguration configuration) { super(credential, configuration); } diff --git a/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java b/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java index 8026d0c..210d68b 100644 --- a/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java +++ b/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadService.java @@ -106,7 +106,7 @@ public class MegaUploadService extends AbstractHttpService implements Service, public Uploader getUploader( String filename, long filesize, MegaUploadUploaderConfiguration configuration) { - return new MegaUploadUploader(filename, filesize, configuration); + return new UploaderImpl(filename, filesize, configuration); } @Override @@ -141,7 +141,7 @@ public class MegaUploadService extends AbstractHttpService implements Service, @Override public Downloader getDownloader(URL url, MegaUploadDownloaderConfiguration configuration) { - return new MegaUploadDownloader(url, configuration); + return new DownloaderImpl(url, configuration); } @Override @@ -173,7 +173,7 @@ public class MegaUploadService extends AbstractHttpService implements Service, @Override public Authenticator getAuthenticator( Credential credential, NullAuthenticatorConfiguration configuration) { - return new MegaUploadAuthenticator(credential, configuration); + return new AuthenticatorImpl(credential, configuration); } @Override @@ -192,13 +192,13 @@ public class MegaUploadService extends AbstractHttpService implements Service, return new CapabilityMatrix(); } - protected class MegaUploadUploader extends + protected class UploaderImpl extends AbstractUploader implements Uploader, LinkedUploadChannelCloseCallback { private Future uploadFuture; - public MegaUploadUploader(String filename, long filesize, + public UploaderImpl(String filename, long filesize, MegaUploadUploaderConfiguration configuration) { super(filename, filesize, configuration); } @@ -229,10 +229,10 @@ public class MegaUploadService extends AbstractHttpService implements Service, } } - protected class MegaUploadDownloader extends + protected class DownloaderImpl extends AbstractHttpDownloader implements Downloader { - public MegaUploadDownloader(URL url, + public DownloaderImpl(URL url, MegaUploadDownloaderConfiguration configuration) { super(url, configuration); } @@ -289,10 +289,10 @@ public class MegaUploadService extends AbstractHttpService implements Service, } } - protected class MegaUploadAuthenticator extends + protected class AuthenticatorImpl extends AbstractAuthenticator implements Authenticator { - public MegaUploadAuthenticator(Credential credential, + public AuthenticatorImpl(Credential credential, NullAuthenticatorConfiguration configuration) { super(credential, configuration); } diff --git a/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadUploaderConfiguration.java b/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadUploaderConfiguration.java index 3e2576a..03fa5af 100644 --- a/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadUploaderConfiguration.java +++ b/httpchannel-service/httpchannel-service-megaupload/src/main/java/com/rogiel/httpchannel/service/impl/MegaUploadUploaderConfiguration.java @@ -2,10 +2,10 @@ package com.rogiel.httpchannel.service.impl; import com.rogiel.httpchannel.service.Uploader.DescriptionableUploaderConfiguration; import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration; -import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadUploader; +import com.rogiel.httpchannel.service.impl.MegaUploadService.UploaderImpl; /** - * Describes an configuration for an {@link MegaUploadUploader} + * Describes an configuration for an {@link UploaderImpl} * * @author Rogiel */ diff --git a/httpchannel-service/httpchannel-service-multiupload/pom.xml b/httpchannel-service/httpchannel-service-multiupload/pom.xml index 07db14a..6dad15d 100644 --- a/httpchannel-service/httpchannel-service-multiupload/pom.xml +++ b/httpchannel-service/httpchannel-service-multiupload/pom.xml @@ -1,21 +1,14 @@ - - 4.0.0 - - httpchannel-service - com.rogiel.httpchannel - 1.0.0 - .. - - httpchannel-service-multiupload - com.rogiel.httpchannel.services - HttpChannel/Service/MultiUpload - Provides upload access to multiupload.com - - - com.rogiel.httpchannel - httpchannel-tests - 1.0.0 - runtime - - + + 4.0.0 + + httpchannel-service + com.rogiel.httpchannel + 1.0.0 + .. + + httpchannel-service-multiupload + com.rogiel.httpchannel.services + HttpChannel/Service/MultiUpload + Provides upload access to multiupload.com \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadService.java b/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadService.java index 31e8853..0f97913 100644 --- a/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadService.java +++ b/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadService.java @@ -86,7 +86,7 @@ public class MultiUploadService extends AbstractHttpService implements Service, MultiUploadUploaderConfiguration configuration) { if (configuration == null) configuration = new MultiUploadUploaderConfiguration(); - return new MultiUploadUploader(filename, filesize, configuration); + return new UploaderImpl(filename, filesize, configuration); } @Override @@ -121,7 +121,7 @@ public class MultiUploadService extends AbstractHttpService implements Service, @Override public Downloader getDownloader(URL url, NullDownloaderConfiguration configuration) { - return new MultiUploaderDownloader(url, configuration); + return new DownloaderImpl(url, configuration); } @Override @@ -151,7 +151,7 @@ public class MultiUploadService extends AbstractHttpService implements Service, @Override public Authenticator getAuthenticator( Credential credential, NullAuthenticatorConfiguration configuration) { - return new MultiUploadAuthenticator(credential, configuration); + return new AuthenticatorImpl(credential, configuration); } @Override @@ -170,13 +170,13 @@ public class MultiUploadService extends AbstractHttpService implements Service, return new CapabilityMatrix(); } - protected class MultiUploadUploader extends + protected class UploaderImpl extends AbstractUploader implements Uploader, LinkedUploadChannelCloseCallback { private Future uploadFuture; - public MultiUploadUploader(String filename, long filesize, + public UploaderImpl(String filename, long filesize, MultiUploadUploaderConfiguration configuration) { super(filename, filesize, configuration); } @@ -216,10 +216,10 @@ public class MultiUploadService extends AbstractHttpService implements Service, } } - protected class MultiUploaderDownloader extends + protected class DownloaderImpl extends AbstractHttpDownloader implements Downloader { - protected MultiUploaderDownloader(URL url, + protected DownloaderImpl(URL url, NullDownloaderConfiguration configuration) { super(url, configuration); } @@ -237,10 +237,10 @@ public class MultiUploadService extends AbstractHttpService implements Service, } } - protected class MultiUploadAuthenticator extends + protected class AuthenticatorImpl extends AbstractAuthenticator implements Authenticator { - public MultiUploadAuthenticator(Credential credential, + public AuthenticatorImpl(Credential credential, NullAuthenticatorConfiguration configuration) { super(credential, configuration); } diff --git a/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadUploaderConfiguration.java b/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadUploaderConfiguration.java index 17437b3..20674e7 100644 --- a/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadUploaderConfiguration.java +++ b/httpchannel-service/httpchannel-service-multiupload/src/main/java/com/rogiel/httpchannel/service/impl/MultiUploadUploaderConfiguration.java @@ -4,10 +4,10 @@ import java.util.EnumSet; import com.rogiel.httpchannel.service.Uploader.DescriptionableUploaderConfiguration; import com.rogiel.httpchannel.service.Uploader.UploaderConfiguration; -import com.rogiel.httpchannel.service.impl.MultiUploadService.MultiUploadUploader; +import com.rogiel.httpchannel.service.impl.MultiUploadService.UploaderImpl; /** - * Describes an configuration for an {@link MultiUploadUploader} + * Describes an configuration for an {@link UploaderImpl} * * @author Rogiel */ diff --git a/httpchannel-service/httpchannel-service-multiupload/src/test/java/com/rogiel/httpchannel/service/impl/MultiUploadServiceTest.java b/httpchannel-service/httpchannel-service-multiupload/src/test/java/com/rogiel/httpchannel/service/impl/MultiUploadServiceTest.java index 303392c..b62a33c 100644 --- a/httpchannel-service/httpchannel-service-multiupload/src/test/java/com/rogiel/httpchannel/service/impl/MultiUploadServiceTest.java +++ b/httpchannel-service/httpchannel-service-multiupload/src/test/java/com/rogiel/httpchannel/service/impl/MultiUploadServiceTest.java @@ -1,32 +1,68 @@ package com.rogiel.httpchannel.service.impl; -import java.net.MalformedURLException; +import java.io.IOException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; -import com.rogiel.httpchannel.service.AbstractServiceTest; -import com.rogiel.httpchannel.service.Credential; -import com.rogiel.httpchannel.service.Service; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; -public class MultiUploadServiceTest extends AbstractServiceTest { - @Override - protected Service createService() { - return new MultiUploadService(); +import com.rogiel.httpchannel.service.DownloadService; +import com.rogiel.httpchannel.util.ChannelUtils; + +public class MultiUploadServiceTest { + public static final Path TEST_UPLOAD_FILE = Paths + .get("src/test/resources/upload-test-file.txt"); + public static final byte[] EXPECTED_FULL_CHECKSUM = new byte[] { 27, -93, + -76, 6, 123, -31, -9, 1, -100, 103, 123, -108, -22, -3, 121, -54, + -127, 27, 43, -8 }; + public static final byte[] EXPECTED_RESUME_CHECKSUM = new byte[] { 39, -29, + -107, -76, -69, -122, -20, 78, -27, -60, 95, -23, 70, -127, -17, + 101, -39, -87, -2, -67 }; + + private MultiUploadService service; + + @Before + public void setUp() throws Exception { + this.service = new MultiUploadService(); } - @Override - protected URL createDownloadURL() throws MalformedURLException { - return new URL("http://www.multiupload.com/QPDUXJDZZY"); + @Test + public void testUploader() throws IOException { + final URL url = ChannelUtils.upload(service, TEST_UPLOAD_FILE); + Assert.assertNotNull(url); + System.out.println("Uploaded file to " + url); } - @Override - protected Credential createValidCredential() { - return null; + @Test + public void testDownloader() throws IOException, NoSuchAlgorithmException { + final byte[] data = ChannelUtils + .toByteArray(((DownloadService) service).getDownloader( + new URL("http://www.multiupload.com/TJOYWB4JEW")) + .openChannel()); + assertChecksum("Downloaded data checksum did not matched", "SHA1", + data, EXPECTED_FULL_CHECKSUM); } - @Override - protected Credential createInvalidCredential() { - return new Credential("invalid-" - + Double.toString(Math.random() * 1000), Double.toString(Math - .random() * Integer.MAX_VALUE)); + @Test + public void testDownloaderResume() throws IOException, + NoSuchAlgorithmException { + final byte[] data = ChannelUtils + .toByteArray(((DownloadService) service).getDownloader( + new URL("http://www.multiupload.com/TJOYWB4JEW")) + .openChannel(50)); + assertChecksum("Downloaded data checksum did not matched", "SHA1", + data, EXPECTED_RESUME_CHECKSUM); + } + + public static void assertChecksum(String message, String algorithm, + byte[] data, byte[] expected) throws NoSuchAlgorithmException { + final MessageDigest md = MessageDigest.getInstance(algorithm); + final byte[] actual = md.digest(data); + Assert.assertArrayEquals(message, expected, actual); } } diff --git a/httpchannel-tests/pom.xml b/httpchannel-service/httpchannel-service-uploadhere/pom.xml similarity index 56% rename from httpchannel-tests/pom.xml rename to httpchannel-service/httpchannel-service-uploadhere/pom.xml index 7cf6180..77dd028 100644 --- a/httpchannel-tests/pom.xml +++ b/httpchannel-service/httpchannel-service-uploadhere/pom.xml @@ -1,23 +1,19 @@ 4.0.0 - httpchannel + httpchannel-service com.rogiel.httpchannel 1.0.0 .. - httpchannel-tests - HttpChannel/Tests - This module contains several test utilities + httpchannel-service-uploadhere + com.rogiel.httpchannel.services + HttpChannel/Service/UploadHere + Provides upload access to uploadhere.com com.rogiel.httpchannel - httpchannel-api - 1.0.0 - - - com.rogiel.httpchannel - httpchannel-util + httpchannel-captcha-recaptcha 1.0.0 diff --git a/httpchannel-service/httpchannel-service-uploadhere/src/main/java/com/rogiel/httpchannel/service/impl/UploadHereService.java b/httpchannel-service/httpchannel-service-uploadhere/src/main/java/com/rogiel/httpchannel/service/impl/UploadHereService.java new file mode 100644 index 0000000..69861ec --- /dev/null +++ b/httpchannel-service/httpchannel-service-uploadhere/src/main/java/com/rogiel/httpchannel/service/impl/UploadHereService.java @@ -0,0 +1,284 @@ +package com.rogiel.httpchannel.service.impl; + +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.regex.Pattern; + +import com.rogiel.httpchannel.captcha.impl.AjaxReCaptchaService; +import com.rogiel.httpchannel.captcha.impl.ReCaptcha; +import com.rogiel.httpchannel.service.AbstractAuthenticator; +import com.rogiel.httpchannel.service.AbstractHttpDownloader; +import com.rogiel.httpchannel.service.AbstractHttpService; +import com.rogiel.httpchannel.service.AbstractUploader; +import com.rogiel.httpchannel.service.AuthenticationService; +import com.rogiel.httpchannel.service.Authenticator; +import com.rogiel.httpchannel.service.AuthenticatorCapability; +import com.rogiel.httpchannel.service.CapabilityMatrix; +import com.rogiel.httpchannel.service.Credential; +import com.rogiel.httpchannel.service.DownloadChannel; +import com.rogiel.httpchannel.service.DownloadListener; +import com.rogiel.httpchannel.service.DownloadService; +import com.rogiel.httpchannel.service.Downloader; +import com.rogiel.httpchannel.service.DownloaderCapability; +import com.rogiel.httpchannel.service.Service; +import com.rogiel.httpchannel.service.ServiceID; +import com.rogiel.httpchannel.service.UploadChannel; +import com.rogiel.httpchannel.service.UploadService; +import com.rogiel.httpchannel.service.Uploader; +import com.rogiel.httpchannel.service.UploaderCapability; +import com.rogiel.httpchannel.service.channel.LinkedUploadChannel; +import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback; +import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration; +import com.rogiel.httpchannel.service.config.NullDownloaderConfiguration; +import com.rogiel.httpchannel.service.config.NullUploaderConfiguration; +import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException; +import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException; +import com.rogiel.httpchannel.service.exception.InvalidCaptchaException; +import com.rogiel.httpchannel.util.PatternUtils; +import com.rogiel.httpchannel.util.htmlparser.HTMLPage; + +/** + * This service handles uploads to UploadKing.com. + * + * @author Rogiel + * @since 1.0 + */ +public class UploadHereService extends AbstractHttpService implements Service, + UploadService, + DownloadService, + AuthenticationService { + /** + * This service ID + */ + public static final ServiceID SERVICE_ID = ServiceID.create("uploadhere"); + + private static final Pattern UPLOAD_URL_PATTERN = Pattern + .compile("http://www([0-9]*)\\.uploadhere\\.com/upload/\\?UPLOAD_IDENTIFIER=[0-9]*"); + private static final Pattern DOWNLOAD_ID_PATTERN = Pattern + .compile("\"downloadid\":\"([0-9a-zA-Z]*)\""); + private static final Pattern DOWNLOAD_URL_PATTERN = Pattern + .compile("http://(www\\.)?uploadhere.\\com/[0-9A-z]*"); + private static final Pattern TIMER_PATTERN = Pattern.compile( + "count = ([0-9]*);", Pattern.COMMENTS); + private static final Pattern DIERCT_DOWNLOAD_URL_PATTERN = Pattern + .compile("(http:\\\\/\\\\/www[0-9]*\\.uploadhere\\.com(:[0-9]*)?\\\\/files\\\\/([0-9A-z]*)\\\\/(.*))\""); + + private static final String INVALID_LOGIN_STRING = "Incorrect username and/or password. Please try again!"; + + private final AjaxReCaptchaService captchaService = new AjaxReCaptchaService(); + + @Override + public ServiceID getID() { + return SERVICE_ID; + } + + @Override + public int getMajorVersion() { + return 1; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public Uploader getUploader(String filename, + long filesize, NullUploaderConfiguration configuration) { + return new UploaderImpl(filename, filesize, configuration); + } + + @Override + public Uploader getUploader(String filename, + long filesize) { + return getUploader(filename, filesize, newUploaderConfiguration()); + } + + @Override + public NullUploaderConfiguration newUploaderConfiguration() { + return NullUploaderConfiguration.SHARED_INSTANCE; + } + + @Override + public long getMaximumFilesize() { + return 1 * 1024 * 1024 * 1024; + } + + @Override + public String[] getSupportedExtensions() { + return null; + } + + @Override + public CapabilityMatrix getUploadCapabilities() { + return new CapabilityMatrix( + UploaderCapability.UNAUTHENTICATED_UPLOAD, + UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD, + UploaderCapability.PREMIUM_ACCOUNT_UPLOAD); + } + + @Override + public Downloader getDownloader(URL url, + NullDownloaderConfiguration configuration) { + return new DownloaderImpl(url, configuration); + } + + @Override + public Downloader getDownloader(URL url) { + return getDownloader(url, newDownloaderConfiguration()); + } + + @Override + public NullDownloaderConfiguration newDownloaderConfiguration() { + return NullDownloaderConfiguration.SHARED_INSTANCE; + } + + @Override + public boolean matchURL(URL url) { + return DOWNLOAD_URL_PATTERN.matcher(url.toString()).matches(); + } + + @Override + public CapabilityMatrix getDownloadCapabilities() { + return new CapabilityMatrix( + DownloaderCapability.UNAUTHENTICATED_DOWNLOAD, + DownloaderCapability.UNAUTHENTICATED_RESUME, + DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD, + DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME); + } + + @Override + public Authenticator getAuthenticator( + Credential credential, NullAuthenticatorConfiguration configuration) { + return new AuthenticatorImpl(credential, configuration); + } + + @Override + public Authenticator getAuthenticator( + Credential credential) { + return getAuthenticator(credential, newAuthenticatorConfiguration()); + } + + @Override + public NullAuthenticatorConfiguration newAuthenticatorConfiguration() { + return NullAuthenticatorConfiguration.SHARED_INSTANCE; + } + + @Override + public CapabilityMatrix getAuthenticationCapability() { + return new CapabilityMatrix(); + } + + protected class UploaderImpl extends + AbstractUploader implements + Uploader, + LinkedUploadChannelCloseCallback { + private Future uploadFuture; + + public UploaderImpl(String filename, long filesize, + NullUploaderConfiguration configuration) { + super(filename, filesize, configuration); + } + + @Override + public UploadChannel openChannel() throws IOException { + final HTMLPage page = get("http://www.uploadhere.com/").asPage(); + + final String userCookie = page.getInputValueById("usercookie"); + final String url = page.findFormAction(UPLOAD_URL_PATTERN); + final String uploadID = page.getInputValue("UPLOAD_IDENTIFIER"); + + final LinkedUploadChannel channel = createLinkedChannel(this); + uploadFuture = multipartPost(url).parameter("file_0", channel) + .parameter("u", userCookie) + .parameter("UPLOAD_IDENTIFIER", uploadID).asStringAsync(); + return waitChannelLink(channel, uploadFuture); + } + + @Override + public String finish() throws IOException { + try { + final String linkId = PatternUtils.find(DOWNLOAD_ID_PATTERN, + uploadFuture.get(), 1); + if (linkId == null) + return null; + return new StringBuilder("http://www.uploadhere.com/").append( + linkId).toString(); + } catch (InterruptedException e) { + return null; + } catch (ExecutionException e) { + if (e.getCause() instanceof IOException) + throw (IOException) e.getCause(); + else + throw new IOException(e.getCause()); + } + } + } + + protected class DownloaderImpl extends + AbstractHttpDownloader implements + Downloader { + public DownloaderImpl(URL url, NullDownloaderConfiguration configuration) { + super(url, configuration); + } + + @Override + public DownloadChannel openChannel(DownloadListener listener, + long position) throws IOException { + HTMLPage page = get(url).asPage(); + + final int waitTime = page.findScriptAsInt(TIMER_PATTERN, 1) * 1000; + + final ReCaptcha captcha = captchaService.create(page.toString()); + if (captcha != null) { + final long start = System.currentTimeMillis(); + resolveCaptcha(captcha); + + final long delta = System.currentTimeMillis() - start; + if (delta < waitTime) + timer(listener, waitTime - delta); + + String content = post(url) + .parameter("recaptcha_challenge_field", captcha.getID()) + .parameter("recaptcha_response_field", + captcha.getAnswer()).asString(); + String downloadLink = PatternUtils.find( + DIERCT_DOWNLOAD_URL_PATTERN, content, 1); + if (downloadLink == null) + throw new InvalidCaptchaException(); + downloadLink = downloadLink.replaceAll(Pattern.quote("\\/"), + "/"); + return download(get(downloadLink).position(position)); + } + throw new DownloadLinkNotFoundException(); + } + } + + protected class AuthenticatorImpl extends + AbstractAuthenticator implements + Authenticator { + public AuthenticatorImpl(Credential credential, + NullAuthenticatorConfiguration configuration) { + super(credential, configuration); + } + + @Override + public void login() throws IOException { + final HTMLPage page = post("http://www.uploadhere.com/login") + .parameter("do", "login") + .parameter("username", credential.getUsername()) + .parameter("password", credential.getPassword()).asPage(); + if (page.contains(INVALID_LOGIN_STRING)) + throw new AuthenticationInvalidCredentialException(); + } + + @Override + public void logout() throws IOException { + post("http://www.uploadking.com/login").parameter("do", "logout") + .request(); + // TODO check logout status + } + } +} diff --git a/httpchannel-service/httpchannel-service-uploadhere/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service b/httpchannel-service/httpchannel-service-uploadhere/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service new file mode 100644 index 0000000..af09d29 --- /dev/null +++ b/httpchannel-service/httpchannel-service-uploadhere/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service @@ -0,0 +1 @@ +com.rogiel.httpchannel.service.impl.UploadKingService \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-uploadhere/src/test/java/com/rogiel/httpchannel/service/impl/UploadHereServiceTest.java b/httpchannel-service/httpchannel-service-uploadhere/src/test/java/com/rogiel/httpchannel/service/impl/UploadHereServiceTest.java new file mode 100644 index 0000000..a523beb --- /dev/null +++ b/httpchannel-service/httpchannel-service-uploadhere/src/test/java/com/rogiel/httpchannel/service/impl/UploadHereServiceTest.java @@ -0,0 +1,62 @@ +package com.rogiel.httpchannel.service.impl; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.rogiel.httpchannel.service.UploaderCapability; +import com.rogiel.httpchannel.util.ChannelUtils; + +public class UploadHereServiceTest { + private UploadHereService service; + + @Before + public void setUp() throws Exception { + service = new UploadHereService(); + } + + @Test + public void testNonLoguedInUploader() throws IOException { + assertTrue( + "This service does not have the capability UploadCapability.UNAUTHENTICATED_UPLOAD", + service.getUploadCapabilities().has( + UploaderCapability.UNAUTHENTICATED_UPLOAD)); + + final Path path = Paths.get("src/test/resources/upload-test-file.txt"); + final URL url = ChannelUtils.upload(service, path); + + Assert.assertNotNull(url); + System.out.println(url); + } + + // @Test + // public void testDownloader() throws IOException { + // service.setCaptchaResolver(new CaptchaResolver() { + // @Override + // public boolean resolve(Captcha rawCaptcha) { + // final ImageCaptcha captcha = (ImageCaptcha) rawCaptcha; + // System.out.println(captcha.getImageURL()); + // try { + // captcha.setAnswer(new BufferedReader(new InputStreamReader( + // System.in)).readLine()); + // System.out.println("Answer is: " + captcha.getAnswer()); + // return true; + // } catch (IOException e) { + // return false; + // } + // } + // }); + // + // final DownloadChannel channel = service.getDownloader( + // new URL("http://www.uploadhere.com/9WCEQF1Q07")).openChannel(); + // System.out.println(new String(ChannelUtils.toByteArray(channel))); + // } +} diff --git a/httpchannel-tests/src/main/resources/upload-test-file.txt b/httpchannel-service/httpchannel-service-uploadhere/src/test/resources/upload-test-file.txt similarity index 100% rename from httpchannel-tests/src/main/resources/upload-test-file.txt rename to httpchannel-service/httpchannel-service-uploadhere/src/test/resources/upload-test-file.txt diff --git a/httpchannel-service/httpchannel-service-uploadking/pom.xml b/httpchannel-service/httpchannel-service-uploadking/pom.xml index ba4ed0a..d58c097 100644 --- a/httpchannel-service/httpchannel-service-uploadking/pom.xml +++ b/httpchannel-service/httpchannel-service-uploadking/pom.xml @@ -10,4 +10,11 @@ com.rogiel.httpchannel.services HttpChannel/Service/UploadKing Provides upload access to uploadking.com + + + com.rogiel.httpchannel + httpchannel-captcha-recaptcha + 1.0.0 + + \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-uploadking/src/main/java/com/rogiel/httpchannel/service/impl/UploadKingService.java b/httpchannel-service/httpchannel-service-uploadking/src/main/java/com/rogiel/httpchannel/service/impl/UploadKingService.java index 74888a7..69c33d9 100644 --- a/httpchannel-service/httpchannel-service-uploadking/src/main/java/com/rogiel/httpchannel/service/impl/UploadKingService.java +++ b/httpchannel-service/httpchannel-service-uploadking/src/main/java/com/rogiel/httpchannel/service/impl/UploadKingService.java @@ -1,11 +1,15 @@ package com.rogiel.httpchannel.service.impl; import java.io.IOException; +import java.net.URL; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.regex.Pattern; +import com.rogiel.httpchannel.captcha.impl.AjaxReCaptchaService; +import com.rogiel.httpchannel.captcha.impl.ReCaptcha; import com.rogiel.httpchannel.service.AbstractAuthenticator; +import com.rogiel.httpchannel.service.AbstractHttpDownloader; import com.rogiel.httpchannel.service.AbstractHttpService; import com.rogiel.httpchannel.service.AbstractUploader; import com.rogiel.httpchannel.service.AuthenticationService; @@ -13,6 +17,11 @@ import com.rogiel.httpchannel.service.Authenticator; import com.rogiel.httpchannel.service.AuthenticatorCapability; import com.rogiel.httpchannel.service.CapabilityMatrix; import com.rogiel.httpchannel.service.Credential; +import com.rogiel.httpchannel.service.DownloadChannel; +import com.rogiel.httpchannel.service.DownloadListener; +import com.rogiel.httpchannel.service.DownloadService; +import com.rogiel.httpchannel.service.Downloader; +import com.rogiel.httpchannel.service.DownloaderCapability; import com.rogiel.httpchannel.service.Service; import com.rogiel.httpchannel.service.ServiceID; import com.rogiel.httpchannel.service.UploadChannel; @@ -22,8 +31,11 @@ import com.rogiel.httpchannel.service.UploaderCapability; import com.rogiel.httpchannel.service.channel.LinkedUploadChannel; import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback; import com.rogiel.httpchannel.service.config.NullAuthenticatorConfiguration; +import com.rogiel.httpchannel.service.config.NullDownloaderConfiguration; import com.rogiel.httpchannel.service.config.NullUploaderConfiguration; import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException; +import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException; +import com.rogiel.httpchannel.service.exception.InvalidCaptchaException; import com.rogiel.httpchannel.util.PatternUtils; import com.rogiel.httpchannel.util.htmlparser.HTMLPage; @@ -35,6 +47,7 @@ import com.rogiel.httpchannel.util.htmlparser.HTMLPage; */ public class UploadKingService extends AbstractHttpService implements Service, UploadService, + DownloadService, AuthenticationService { /** * This service ID @@ -45,9 +58,17 @@ public class UploadKingService extends AbstractHttpService implements Service, .compile("http://www([0-9]*)\\.uploadking\\.com/upload/\\?UPLOAD_IDENTIFIER=[0-9]*"); private static final Pattern DOWNLOAD_ID_PATTERN = Pattern .compile("\"downloadid\":\"([0-9a-zA-Z]*)\""); + private static final Pattern DOWNLOAD_URL_PATTERN = Pattern + .compile("http://(www\\.)?uploadking.\\com/[0-9A-z]*"); + private static final Pattern TIMER_PATTERN = Pattern.compile( + "count = ([0-9]*);", Pattern.COMMENTS); + private static final Pattern DIERCT_DOWNLOAD_URL_PATTERN = Pattern + .compile("(http:\\\\/\\\\/www[0-9]*\\.uploadking\\.com(:[0-9]*)?\\\\/files\\\\/([0-9A-z]*)\\\\/(.*))\""); private static final String INVALID_LOGIN_STRING = "Incorrect username and/or password. Please try again!"; + private final AjaxReCaptchaService captchaService = new AjaxReCaptchaService(); + @Override public ServiceID getID() { return SERVICE_ID; @@ -66,7 +87,7 @@ public class UploadKingService extends AbstractHttpService implements Service, @Override public Uploader getUploader(String filename, long filesize, NullUploaderConfiguration configuration) { - return new UploadKingUploader(filename, filesize, configuration); + return new UploaderImpl(filename, filesize, configuration); } @Override @@ -98,10 +119,40 @@ public class UploadKingService extends AbstractHttpService implements Service, UploaderCapability.PREMIUM_ACCOUNT_UPLOAD); } + @Override + public Downloader getDownloader(URL url, + NullDownloaderConfiguration configuration) { + return new DownloaderImpl(url, configuration); + } + + @Override + public Downloader getDownloader(URL url) { + return getDownloader(url, newDownloaderConfiguration()); + } + + @Override + public NullDownloaderConfiguration newDownloaderConfiguration() { + return NullDownloaderConfiguration.SHARED_INSTANCE; + } + + @Override + public boolean matchURL(URL url) { + return DOWNLOAD_URL_PATTERN.matcher(url.toString()).matches(); + } + + @Override + public CapabilityMatrix getDownloadCapabilities() { + return new CapabilityMatrix( + DownloaderCapability.UNAUTHENTICATED_DOWNLOAD, + DownloaderCapability.UNAUTHENTICATED_RESUME, + DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD, + DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME); + } + @Override public Authenticator getAuthenticator( Credential credential, NullAuthenticatorConfiguration configuration) { - return new UploadKingAuthenticator(credential, configuration); + return new AuthenticatorImpl(credential, configuration); } @Override @@ -120,13 +171,13 @@ public class UploadKingService extends AbstractHttpService implements Service, return new CapabilityMatrix(); } - protected class UploadKingUploader extends + protected class UploaderImpl extends AbstractUploader implements Uploader, LinkedUploadChannelCloseCallback { private Future uploadFuture; - public UploadKingUploader(String filename, long filesize, + public UploaderImpl(String filename, long filesize, NullUploaderConfiguration configuration) { super(filename, filesize, configuration); } @@ -163,10 +214,50 @@ public class UploadKingService extends AbstractHttpService implements Service, } } - protected class UploadKingAuthenticator extends + protected class DownloaderImpl extends + AbstractHttpDownloader implements + Downloader { + public DownloaderImpl(URL url, NullDownloaderConfiguration configuration) { + super(url, configuration); + } + + @Override + public DownloadChannel openChannel(DownloadListener listener, + long position) throws IOException { + HTMLPage page = get(url).asPage(); + + final int waitTime = page.findScriptAsInt(TIMER_PATTERN, 1) * 1000; + + final ReCaptcha captcha = captchaService.create(page.toString()); + if (captcha != null) { + final long start = System.currentTimeMillis(); + + resolveCaptcha(captcha); + + final long delta = System.currentTimeMillis() - start; + if (delta < waitTime) + timer(listener, waitTime - delta); + + String content = post(url) + .parameter("recaptcha_challenge_field", captcha.getID()) + .parameter("recaptcha_response_field", + captcha.getAnswer()).asString(); + String downloadLink = PatternUtils.find( + DIERCT_DOWNLOAD_URL_PATTERN, content, 1); + if (downloadLink == null) + throw new InvalidCaptchaException(); + downloadLink = downloadLink.replaceAll(Pattern.quote("\\/"), + "/"); + return download(get(downloadLink).position(position)); + } + throw new DownloadLinkNotFoundException(); + } + } + + protected class AuthenticatorImpl extends AbstractAuthenticator implements Authenticator { - public UploadKingAuthenticator(Credential credential, + public AuthenticatorImpl(Credential credential, NullAuthenticatorConfiguration configuration) { super(credential, configuration); } diff --git a/httpchannel-service/httpchannel-service-uploadking/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service b/httpchannel-service/httpchannel-service-uploadking/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service index 4013beb..af09d29 100644 --- a/httpchannel-service/httpchannel-service-uploadking/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service +++ b/httpchannel-service/httpchannel-service-uploadking/src/main/resources/META-INF/services/com.rogiel.httpchannel.service.Service @@ -1 +1 @@ -com.rogiel.httpchannel.service.impl.MultiUploadService \ No newline at end of file +com.rogiel.httpchannel.service.impl.UploadKingService \ No newline at end of file diff --git a/httpchannel-service/httpchannel-service-uploadking/src/test/java/com/rogiel/httpchannel/service/impl/UploadKingServiceTest.java b/httpchannel-service/httpchannel-service-uploadking/src/test/java/com/rogiel/httpchannel/service/impl/UploadKingServiceTest.java index 99dafd8..9d783e7 100644 --- a/httpchannel-service/httpchannel-service-uploadking/src/test/java/com/rogiel/httpchannel/service/impl/UploadKingServiceTest.java +++ b/httpchannel-service/httpchannel-service-uploadking/src/test/java/com/rogiel/httpchannel/service/impl/UploadKingServiceTest.java @@ -36,4 +36,27 @@ public class UploadKingServiceTest { Assert.assertNotNull(url); System.out.println(url); } + + // @Test + // public void testDownloader() throws IOException { + // service.setCaptchaResolver(new CaptchaResolver() { + // @Override + // public boolean resolve(Captcha rawCaptcha) { + // final ImageCaptcha captcha = (ImageCaptcha) rawCaptcha; + // System.out.println(captcha.getImageURL()); + // try { + // captcha.setAnswer(new BufferedReader(new InputStreamReader( + // System.in)).readLine()); + // System.out.println("Answer is: " + captcha.getAnswer()); + // return true; + // } catch (IOException e) { + // return false; + // } + // } + // }); + // + // final DownloadChannel channel = service.getDownloader( + // new URL("http://www.uploadking.com/WM3PHD9JAY")).openChannel(512); + // System.out.println(new String(ChannelUtils.toByteArray(channel))); + // } } diff --git a/httpchannel-service/pom.xml b/httpchannel-service/pom.xml index c920672..83db7e5 100644 --- a/httpchannel-service/pom.xml +++ b/httpchannel-service/pom.xml @@ -10,6 +10,9 @@ httpchannel-service pom + HttpChannel/Service + Parent module that all service implementations should inherit + httpchannel-service-megaupload httpchannel-service-hotfile @@ -28,6 +31,4 @@ 1.0.0 - HttpChannel/Service - Parent module that all service implementations should inherit \ No newline at end of file diff --git a/httpchannel-tests/src/main/java/com/rogiel/httpchannel/service/AbstractServiceTest.java b/httpchannel-tests/src/main/java/com/rogiel/httpchannel/service/AbstractServiceTest.java deleted file mode 100644 index c1d587f..0000000 --- a/httpchannel-tests/src/main/java/com/rogiel/httpchannel/service/AbstractServiceTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * This file is part of seedbox . - * - * seedbox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * seedbox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with seedbox. If not, see . - */ -package com.rogiel.httpchannel.service; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; - -import junit.framework.Assert; - -import org.junit.Before; -import org.junit.Test; - -import com.rogiel.httpchannel.service.exception.AuthenticationInvalidCredentialException; -import com.rogiel.httpchannel.util.ChannelUtils; -import com.rogiel.httpchannel.util.ChecksumUtils; - -public abstract class AbstractServiceTest { - public static final Path TEST_UPLOAD_FILE = Paths - .get("src/main/resources/upload-test-file.txt"); - public static final byte[] EXPECTED_FULL_CHECKSUM = new byte[] { 27, -93, - -76, 6, 123, -31, -9, 1, -100, 103, 123, -108, -22, -3, 121, -54, - -127, 27, 43, -8 }; - public static final byte[] EXPECTED_RESUME_CHECKSUM = new byte[] { 39, -29, - -107, -76, -69, -122, -20, 78, -27, -60, 95, -23, 70, -127, -17, - 101, -39, -87, -2, -67 }; - - private Service service; - - private URL downloadURL; - - private Credential validCredential; - private Credential invalidCredential; - - @Before - public void setUp() throws Exception { - this.service = createService(); - downloadURL = createDownloadURL(); - validCredential = createValidCredential(); - invalidCredential = createInvalidCredential(); - } - - protected abstract Service createService(); - - protected Credential createValidCredential() { - return null; - } - - protected Credential createInvalidCredential() { - return null; - } - - protected URL createDownloadURL() throws MalformedURLException { - return null; - } - - @Test - public void testUnauthenticatedUpload() throws IOException { - if (!(service instanceof UploadService)) - return; - assertTrue( - "This service does not have the capability UploadCapability.UNAUTHENTICATED_UPLOAD", - ((UploadService) service).getUploadCapabilities().has( - UploaderCapability.UNAUTHENTICATED_UPLOAD)); - - final URL url = ChannelUtils.upload((UploadService) service, - TEST_UPLOAD_FILE); - - Assert.assertNotNull(url); - System.out.println("Uploaded file to " + url); - } - - @Test - public void testAuthenticatedUpload() throws IOException { - if (validCredential == null) - return; - if (!(service instanceof UploadService)) - return; - if (!(service instanceof AuthenticationService)) - fail("The servide does not support authentication!"); - - assertTrue( - "This service does not have the capability UploadCapability.NON_PREMIUM_ACCOUNT_UPLOAD", - ((UploadService) service).getUploadCapabilities().has( - UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD)); - - ((AuthenticationService) service).getAuthenticator(validCredential) - .login(); - - final URL url = ChannelUtils.upload((UploadService) service, - TEST_UPLOAD_FILE); - - Assert.assertNotNull(url); - System.out.println("Uploaded file to " + url); - } - - @Test - public void testUnauthenticatedDownload() throws IOException, - NoSuchAlgorithmException { - if (!(service instanceof DownloadService)) - return; - assertTrue( - "This service does not have the capability DownloaderCapability.UNAUTHENTICATED_DOWNLOAD", - ((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.UNAUTHENTICATED_DOWNLOAD)); - - final byte[] data = ChannelUtils - .toByteArray(((DownloadService) service).getDownloader( - downloadURL).openChannel()); - ChecksumUtils.assertChecksum( - "Downloaded data checksum did not matched", "SHA1", data, - EXPECTED_FULL_CHECKSUM); - } - - @Test - public void testUnauthenticatedDownloadResume() throws IOException, - NoSuchAlgorithmException { - if (!(service instanceof DownloadService)) - return; - if (!((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.UNAUTHENTICATED_RESUME)) - return; - - assertTrue( - "This service does not have the capability DownloaderCapability.UNAUTHENTICATED_DOWNLOAD", - ((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.UNAUTHENTICATED_DOWNLOAD)); - - final byte[] data = ChannelUtils - .toByteArray(((DownloadService) service).getDownloader( - downloadURL).openChannel(50)); - ChecksumUtils.assertChecksum( - "Downloaded data checksum did not matched", "SHA1", data, - EXPECTED_RESUME_CHECKSUM); - } - - @Test - public void testAuthenticatedDownload() throws IOException, - NoSuchAlgorithmException { - if (validCredential == null) - return; - if (!(service instanceof DownloadService)) - return; - if (!(service instanceof AuthenticationService)) - fail("The service does not support authentication!"); - - assertTrue( - "This service does not have the capability DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD", - ((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD)); - - ((AuthenticationService) service).getAuthenticator(validCredential) - .login(); - - final byte[] data = ChannelUtils - .toByteArray(((DownloadService) service).getDownloader( - downloadURL).openChannel()); - ChecksumUtils.assertChecksum( - "Downloaded data checksum did not matched", "SHA1", data, - EXPECTED_FULL_CHECKSUM); - } - - @Test - public void testAuthenticatedDownloadResume() throws IOException, - NoSuchAlgorithmException { - if (validCredential == null) - return; - if (!(service instanceof DownloadService)) - return; - if (!(service instanceof AuthenticationService)) - fail("The service does not support authentication!"); - if (!((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.NON_PREMIUM_ACCOUNT_RESUME)) - return; - - assertTrue( - "This service does not have the capability DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD", - ((DownloadService) service).getDownloadCapabilities().has( - DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD)); - - ((AuthenticationService) service).getAuthenticator(validCredential) - .login(); - - final byte[] data = ChannelUtils - .toByteArray(((DownloadService) service).getDownloader( - downloadURL).openChannel(50)); - ChecksumUtils.assertChecksum( - "Downloaded data checksum did not matched", "SHA1", data, - EXPECTED_RESUME_CHECKSUM); - } - - @Test - public void testAuthenticatorWithValidCredential() throws IOException { - if (validCredential == null) - return; - if (!(service instanceof AuthenticationService)) - return; - - ((AuthenticationService) service).getAuthenticator(validCredential) - .login(); - } - - @Test - public void testAuthenticatorWithInvalidCredential() throws IOException { - if (invalidCredential == null) - return; - if (!(service instanceof AuthenticationService)) - return; - try { - ((AuthenticationService) service).getAuthenticator( - invalidCredential).login(); - } catch (AuthenticationInvalidCredentialException e) { - return; - } - fail("This login attept should have failed!"); - } -} diff --git a/httpchannel-tests/src/main/java/com/rogiel/httpchannel/util/ChecksumUtils.java b/httpchannel-tests/src/main/java/com/rogiel/httpchannel/util/ChecksumUtils.java deleted file mode 100644 index 754ad74..0000000 --- a/httpchannel-tests/src/main/java/com/rogiel/httpchannel/util/ChecksumUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.rogiel.httpchannel.util; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.junit.Assert; - -public class ChecksumUtils { - public static void assertChecksum(String message, String algorithm, - byte[] data, byte[] expected) throws NoSuchAlgorithmException { - final MessageDigest md = MessageDigest.getInstance(algorithm); - final byte[] actual = md.digest(data); - Assert.assertArrayEquals(message, expected, actual); - } -} diff --git a/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractHTMLImageCaptchaService.java b/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractHTMLImageCaptchaService.java new file mode 100644 index 0000000..da7194d --- /dev/null +++ b/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractHTMLImageCaptchaService.java @@ -0,0 +1,26 @@ +/** + * + */ +package com.rogiel.httpchannel.captcha; + +import java.io.IOException; + +import com.rogiel.httpchannel.util.htmlparser.HTMLPage; + +/** + * @author Rogiel + * + */ +public abstract class AbstractHTMLImageCaptchaService + extends AbstractImageCaptchaService { + @Override + public final C create(String html) { + try { + return create(HTMLPage.parse(html)); + } catch (IOException e) { + return null; + } + } + + public abstract C create(HTMLPage page) throws IOException; +} diff --git a/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractImageCaptchaService.java b/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractImageCaptchaService.java index ca0ff58..f5b9de8 100644 --- a/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractImageCaptchaService.java +++ b/httpchannel-util/src/main/java/com/rogiel/httpchannel/captcha/AbstractImageCaptchaService.java @@ -3,14 +3,12 @@ */ package com.rogiel.httpchannel.captcha; -import java.io.IOException; import java.net.URL; import com.rogiel.httpchannel.http.GetRequest; import com.rogiel.httpchannel.http.HttpContext; import com.rogiel.httpchannel.http.PostMultipartRequest; import com.rogiel.httpchannel.http.PostRequest; -import com.rogiel.httpchannel.util.htmlparser.HTMLPage; /** * @author Rogiel @@ -20,17 +18,6 @@ public abstract class AbstractImageCaptchaService { protected final HttpContext http = new HttpContext(); - @Override - public final C create(String html) { - try { - return create(HTMLPage.parse(html)); - } catch (IOException e) { - return null; - } - } - - public abstract C create(HTMLPage page) throws IOException; - @Override public boolean resolve(C captcha) { return false; diff --git a/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpDownloader.java b/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpDownloader.java index 37db7c5..f1c1e68 100644 --- a/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpDownloader.java +++ b/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpDownloader.java @@ -22,10 +22,12 @@ import java.net.URL; import org.apache.commons.io.FilenameUtils; import org.apache.http.Header; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import com.rogiel.httpchannel.http.Request; import com.rogiel.httpchannel.service.Downloader.DownloaderConfiguration; import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel; +import com.rogiel.httpchannel.service.exception.DownloadLinkNotFoundException; import com.rogiel.httpchannel.util.ThreadUtils; /** @@ -58,6 +60,11 @@ public abstract class AbstractHttpDownloader protected InputStreamDownloadChannel download(Request request) throws IOException { final HttpResponse response = request.request(); + if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK + || response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED || response + .getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT)) + throw new DownloadLinkNotFoundException(); + final String filename = FilenameUtils.getName(request.getURL()); final long contentLength = getContentLength(response); return createInputStreamChannel(response.getEntity().getContent(), diff --git a/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java b/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java index 0f3feda..dfbed49 100644 --- a/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java +++ b/httpchannel-util/src/main/java/com/rogiel/httpchannel/service/AbstractHttpService.java @@ -56,6 +56,10 @@ public abstract class AbstractHttpService extends AbstractService implements return http.post(url); } + public PostRequest post(URL url) { + return post(url.toString()); + } + public PostMultipartRequest multipartPost(String url) { return http.multipartPost(url); } diff --git a/pom.xml b/pom.xml index a1a6fe5..bc9d52d 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ httpchannel-service httpchannel-util httpchannel-channelcopy - httpchannel-tests + httpchannel-capcha