diff --git a/core/build.sbt b/core/build.sbt index d1ec4f60..43d4a7ed 100644 --- a/core/build.sbt +++ b/core/build.sbt @@ -4,7 +4,7 @@ description := "Core Dispatch module wrapping async-http-client" libraryDependencies += - "org.asynchttpclient" % "async-http-client" % "2.10.4" + "org.asynchttpclient" % "async-http-client" % "3.0.0" enablePlugins(BuildInfoPlugin) diff --git a/core/src/main/scala/as/oauth/token.scala b/core/src/main/scala/as/oauth/token.scala deleted file mode 100644 index 8fa57e58..00000000 --- a/core/src/main/scala/as/oauth/token.scala +++ /dev/null @@ -1,26 +0,0 @@ -package dispatch.as.oauth - -import org.asynchttpclient.Response -import org.asynchttpclient.oauth.RequestToken - -object Token extends (Response => Either[String, RequestToken]) { - def apply(res: Response) = tokenDecode(dispatch.as.String(res)) - private def decode(str: String) = java.net.URLDecoder.decode(str, "utf-8") - private def formDecode(str: String) = - (for (pair <- str.trim.split('&')) - yield pair.split('=') - ).collect { - case Array(key, value) => decode(key) -> decode(value) - case Array(key) => decode(key) -> "" - } - - private def tokenDecode(str: String) = { - val params = formDecode(str) - (for { - ("oauth_token", tok) <- params - ("oauth_token_secret", secret) <- params - } yield new RequestToken(tok, secret)).headOption.toRight { - "No token found in response: \n\n" + str - } - } -} diff --git a/core/src/main/scala/defaults.scala b/core/src/main/scala/defaults.scala index 16461702..246999f0 100644 --- a/core/src/main/scala/defaults.scala +++ b/core/src/main/scala/defaults.scala @@ -4,6 +4,8 @@ import io.netty.util.{HashedWheelTimer, Timer} import org.asynchttpclient.DefaultAsyncHttpClientConfig.Builder import org.asynchttpclient._ +import java.time.Duration + object Defaults { implicit def executor = scala.concurrent.ExecutionContext.Implicits.global @@ -26,9 +28,11 @@ private[dispatch] object InternalDefaults { private object BasicDefaults extends Defaults { lazy val timer = new HashedWheelTimer() + private val userAgent = "Dispatch/%s" format BuildInfo.version + private val infinite = Duration.ofMillis(-1) def builder: Builder = new DefaultAsyncHttpClientConfig.Builder() - .setUserAgent("Dispatch/%s" format BuildInfo.version) - .setRequestTimeout(-1) // don't timeout streaming connections + .setUserAgent(userAgent) + .setRequestTimeout(infinite) // don't timeout streaming connections .setUseProxyProperties(true) } diff --git a/core/src/main/scala/oauth/exchange.scala b/core/src/main/scala/oauth/exchange.scala deleted file mode 100644 index 58a09e24..00000000 --- a/core/src/main/scala/oauth/exchange.scala +++ /dev/null @@ -1,97 +0,0 @@ -package dispatch.oauth - -import dispatch._ -import io.netty.handler.codec.http.HttpHeaderNames -import org.asynchttpclient._ -import org.asynchttpclient.oauth._ -import java.util.Base64 - -import scala.concurrent.{ExecutionContext, Future} - -trait SomeHttp { - def http: HttpExecutor -} - -trait SomeConsumer { - def consumer: ConsumerKey -} - -trait SomeEndpoints { - def requestToken: String - - def accessToken: String - - def authorize: String -} - -trait SomeCallback { - def callback: String -} - -trait Exchange { - self: SomeHttp - with SomeConsumer - with SomeCallback - with SomeEndpoints => - - private val oauthSignaturePattern = ".*[, ]oauth_signature=\"([A-Za-z0-9%._~()'!*:@,;-]*)\".*".r - - private val random = new java.util.Random(System.identityHashCode(this) + - System.currentTimeMillis) - private val nonceBuffer = Array.fill[Byte](16)(0) - - def generateNonce = nonceBuffer.synchronized { - random.nextBytes(nonceBuffer) - Base64.getEncoder().encodeToString(nonceBuffer) - } - - def message[A](promised: Future[A], ctx: String) - (implicit executor: ExecutionContext) = - for (exc <- promised.either.left) - yield "Unexpected problem fetching %s:\n%s".format(ctx, exc.getMessage) - - def fetchRequestToken(implicit executor: ExecutionContext) - : Future[Either[String, RequestToken]] = { - val promised = http( - url(requestToken) - << Map("oauth_callback" -> callback) - <@ (consumer) - > as.oauth.Token - ) - for (eth <- message(promised, "request token")) yield eth.joinRight - } - - def signedAuthorize(reqToken: RequestToken): String = { - - val calc = new OAuthSignatureCalculator(consumer, reqToken) - val unsigned = url(authorize) < reqToken.getKey) - - val reqBuilder: RequestBuilder = new RequestBuilder - reqBuilder.setUrl(unsigned.url) - - val req: Request = reqBuilder.build() - calc.calculateAndAddSignature(req, reqBuilder) - - val authHeader = reqBuilder.build().getHeaders.get(HttpHeaderNames.AUTHORIZATION) - - val authSignature: String = authHeader match { - case oauthSignaturePattern(signature: String) => signature - case _ => "" // no match - } - - (unsigned < authSignature)).url - } - - def fetchAccessToken(reqToken: RequestToken, verifier: String) - (implicit executor: ExecutionContext) - : Future[Either[String, RequestToken]] = { - val promised = http( - url(accessToken) - << Map("oauth_verifier" -> verifier) - <@ (consumer, reqToken) - > as.oauth.Token - ) - for (eth <- message(promised, "access token")) yield eth.joinRight - } - -} diff --git a/core/src/main/scala/oauth/package.scala b/core/src/main/scala/oauth/package.scala deleted file mode 100644 index 84836d28..00000000 --- a/core/src/main/scala/oauth/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -package dispatch - -package object oauth { - implicit def implySigningVerbs(builder: Req) = - new SigningVerbs(builder) -} diff --git a/core/src/main/scala/oauth/requests.scala b/core/src/main/scala/oauth/requests.scala deleted file mode 100644 index 6c705b0e..00000000 --- a/core/src/main/scala/oauth/requests.scala +++ /dev/null @@ -1,20 +0,0 @@ -package dispatch.oauth - -import dispatch._ -import org.asynchttpclient.oauth._ - -class SigningVerbs(val subject: Req) extends RequestVerbs { - val emptyToken = new RequestToken(null, "") - - def sign(consumer: ConsumerKey, token: RequestToken = emptyToken) = { - val calc = new OAuthSignatureCalculator(consumer, token) - subject underlying { r => - calc.calculateAndAddSignature(r.build, r) - r - } - } - - def <@(consumer: ConsumerKey, token: RequestToken = emptyToken) = - sign(consumer, token) - -} diff --git a/core/src/test/scala/oauth/exchange.scala b/core/src/test/scala/oauth/exchange.scala deleted file mode 100644 index 8222b63b..00000000 --- a/core/src/test/scala/oauth/exchange.scala +++ /dev/null @@ -1,70 +0,0 @@ -package dispatch.oauth.spec - -import org.asynchttpclient.oauth.{ConsumerKey, RequestToken} -import org.scalacheck.Gen.listOf -import org.scalacheck.Prop.forAll -import org.scalacheck.{Gen, Properties} - -/** - * Tests for oauth / exchange. - * - * @author Erik-Berndt Scheper - * @since 25-01-2017 - * - */ -object ExchangeSpecification extends Properties("String") { - - private val safeChars = "[A-Za-z0-9%._~()'!*:@,;-]*" - private val urlPattern = s"(.*)[?]oauth_token=($safeChars)[&]oauth_signature=($safeChars)".r - - private val validKeyString: Gen[String] = listOf(Gen.alphaNumChar).map(_.mkString) - - property("signedAuthorize") = forAll(validKeyString, validKeyString) { (keyValue: String, tokenValue: String) => - import dispatch._ - import dispatch.oauth._ - - trait DropboxHttp extends SomeHttp { - def http: HttpExecutor = Http.default - } - - trait DropboxConsumer extends SomeConsumer { - def consumer: ConsumerKey = new ConsumerKey(keyValue, tokenValue) - } - - trait DropboxCallback extends SomeCallback { - def callback: String = "oob" - } - - trait DropboxEndpoints extends SomeEndpoints { - def requestToken: String = "https://api.dropbox.com/1/oauth/request_token" - - def accessToken: String = "https://www.dropbox.com/1/oauth/authorize" - - def authorize: String = "https://api.dropbox.com/1/oauth/access_token" - } - - object DropboxExchange extends Exchange - with DropboxHttp with DropboxConsumer with DropboxCallback with DropboxEndpoints - - val token = new RequestToken(keyValue, tokenValue) - val url = DropboxExchange.signedAuthorize(token) - - val urlMatcher = url match { - case urlPattern(path: String, authToken: String, signature: String) => - (path, authToken, signature) - case _ => - ("", "", "") // no match - } - - val urlPath = urlMatcher._1 - val authToken = urlMatcher._2 - val authSignature = urlMatcher._3 - - urlPath.equals(DropboxExchange.authorize) && - authToken.length >= keyValue.length && - authToken.matches(safeChars) && - authSignature.length > 0 && - authSignature.matches(safeChars) - } - -}