Last active
December 22, 2015 12:39
-
-
Save tototoshi/6473958 to your computer and use it in GitHub Desktop.
Retrieve request token asynchronously
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.github.tototoshi.oauth | |
import com.ning.http.client._ | |
import javax.crypto.Mac | |
import javax.crypto.spec.SecretKeySpec | |
import java.net.URLEncoder | |
import org.apache.commons.codec.binary.Base64 | |
import scala.concurrent.{Future, Promise} | |
import com.github.kxbmap.configs._ | |
import com.typesafe.config.ConfigFactory | |
import scala.util.parsing.combinator._ | |
object Main { | |
private val config = ConfigFactory.load() | |
private val signatureMethod = "HMAC-SHA1" | |
private val oauthVersion = "1.0a" | |
private val consumerKey = config.get[String]("twitter.consumer.key") | |
private val consumerSecret = config.get[String]("twitter.consumer.secret") | |
private val requestTokenUrl = "https://api.twitter.com/oauth/request_token" | |
case class RequestToken(token: String, tokenSecret: String, callbackConfirmed: Boolean) | |
object RequestTokenParser extends RegexParsers { | |
def oauthToken = "oauth_token" ~ "=" ~> """\w+""".r | |
def oauthTokenSecret = "oauth_token_secret" ~ "=" ~> """\w+""".r | |
def t = "true" ^^ { _ => true } | |
def f = "false" ^^ { _ => false } | |
def oauthCallbackConfirmed = "oauth_callback_confirmed" ~ "=" ~> (t | f) | |
def response = oauthToken ~ ("&" ~> oauthTokenSecret) ~ ("&" ~> oauthCallbackConfirmed) ^^ { | |
case token ~ secret ~ confirmed => RequestToken(token, secret, confirmed) | |
} | |
def parse(in: String) = parseAll(response, in) | |
} | |
class RequestTokenParseException(message: String) extends Exception(message) | |
def main(args: Array[String]): Unit = { | |
import scala.concurrent.ExecutionContext.Implicits.global | |
val client = new AsyncHttpClient() | |
val token = retrieveRequestToken(client) | |
token.onSuccess { | |
case token => println(token) | |
} | |
token.onFailure { | |
case e => e.printStackTrace() | |
} | |
token.onComplete { _ => | |
client.close() | |
} | |
} | |
def retrieveRequestToken(client: AsyncHttpClient): Future[RequestToken] = { | |
val unsignedParams = paramsForRequestToken | |
val signedRequestParams = sign(unsignedParams) | |
val url = requestTokenUrl + "?" + signedRequestParams | |
var result = Promise[RequestToken]() | |
client.prepareGet(url).execute(new AsyncCompletionHandler[Response]() { | |
override def onCompleted(response: Response): Response = { | |
val body = response.getResponseBody | |
val parseResult = RequestTokenParser.parse(body) | |
if (parseResult.successful) { | |
result.success(parseResult.get) | |
} else { | |
result.failure(new RequestTokenParseException("Parse Failed: " + body)) | |
} | |
response | |
} | |
override def onThrowable(t: Throwable) = { | |
result.failure(t) | |
} | |
}) | |
result.future | |
} | |
private def sign(unsigned: String): String = { | |
def getSignature(signatureBaseString: String): String = { | |
val algorithm = "HmacSHA1" | |
val mac = Mac.getInstance(algorithm) | |
val keyString = consumerSecret + "&" | |
val key = new SecretKeySpec(keyString.getBytes(), algorithm) | |
mac.init(key) | |
val digest = mac.doFinal(signatureBaseString.getBytes()) | |
URLEncoder.encode(Base64.encodeBase64String(digest), "UTF-8") | |
} | |
val baseString = | |
"GET&" + URLEncoder.encode(requestTokenUrl, "UTF-8") + "&" + URLEncoder.encode(unsigned, "UTF-8") | |
unsigned + "&" + "oauth_signature" + "=" + getSignature(baseString) | |
} | |
private def paramsForRequestToken: String = { | |
def nonce = (1 to 8).map(_ => scala.util.Random.nextPrintableChar).mkString | |
val params = Map( | |
"oauth_consumer_key" -> consumerKey, | |
"oauth_nonce" -> nonce, | |
"oauth_signature_method" -> signatureMethod, | |
"oauth_timestamp" -> (System.currentTimeMillis() / 1000).toString, | |
"oauth_version" -> oauthVersion | |
) | |
params.toList.sorted.map{ case (k, v) => k + "=" + URLEncoder.encode(v, "UTF-8") }.mkString("&") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sbt._ | |
import sbt.Keys._ | |
object ScalaoauthasyncBuild extends Build { | |
lazy val scalaoauthasync = Project( | |
id = "scala-oauth-async", | |
base = file("."), | |
settings = Project.defaultSettings ++ Seq( | |
name := "scala-oauth-async", | |
organization := "com.github.tototoshi", | |
version := "0.1-SNAPSHOT", | |
scalaVersion := "2.10.2", | |
libraryDependencies ++= Seq( | |
"com.ning" % "async-http-client" % "1.7.19", | |
"commons-codec" % "commons-codec" % "1.8", | |
"com.github.kxbmap" %% "configs" % "0.2.0" | |
) | |
) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment