This repository has been archived by the owner on Apr 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
/
Signature.kt
112 lines (90 loc) · 3.79 KB
/
Signature.kt
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
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.baulsupp.okurl.services.twitter.joauth
import com.baulsupp.okurl.services.twitter.TwitterAuthInterceptor
import com.baulsupp.okurl.services.twitter.TwitterCredentials
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.RequestBody
import okio.Buffer
import java.nio.charset.Charset
import java.security.SecureRandom
import java.time.Clock
import java.util.logging.Level
import java.util.logging.Logger
class Signature(
private val clock: Clock = Clock.systemDefaultZone(),
private val random: () -> Long = { SecureRandom().nextLong() }
) {
private fun quoted(str: String): String {
return "\"" + str + "\""
}
private fun generateTimestamp(): Long {
val timestamp = clock.millis()
return timestamp / 1000
}
private fun generateNonce(): String {
return java.lang.Long.toString(Math.abs(random())) + clock.millis()
}
fun generateAuthorization(request: Request, credentials: TwitterCredentials): String {
val timestampSecs = generateTimestamp()
val nonce = generateNonce()
val oAuth1Params = OAuthParams.OAuth1Params(
credentials.token, credentials.consumerKey!!, nonce, timestampSecs,
java.lang.Long.toString(timestampSecs), "", OAuthParams.HMAC_SHA1,
OAuthParams.ONE_DOT_OH
)
val javaParams = mutableListOf<Pair<String, String>>()
val queryParamNames = request.url.queryParameterNames
for (queryParam in queryParamNames) {
val values = request.url.queryParameterValues(queryParam)
values.mapTo(javaParams) {
Pair(UrlCodec.encode(queryParam)!!, UrlCodec.encode(it)!!)
}
}
if (request.method == "POST") {
val body: RequestBody = request.body!!
if (body is FormBody) {
(0 until body.size).mapTo(javaParams) {
Pair(body.encodedName(it), body.encodedValue(it))
}
} else if (isFormContentType(request)) {
val buffer = Buffer()
body.writeTo(buffer)
val encodedBody = buffer.readString(Charset.forName("UTF-8"))
val handler = KeyValueHandler.DuplicateKeyValueHandler()
val bodyParser = StandardKeyValueParser("&", "=")
bodyParser.parse(encodedBody, listOf<KeyValueHandler>(handler))
javaParams.addAll(handler.toList())
}
}
val normalized = StandardNormalizer.normalize(
if (request.isHttps) "https" else "http", request.url.host, request.url.port,
request.method, request.url.encodedPath, javaParams, oAuth1Params
)
log.log(Level.FINE, "normalised $normalized")
log.log(Level.FINE, "secret " + credentials.secret)
log.log(Level.FINE, "consumerSecret " + credentials.consumerSecret)
val signature =
StandardSigner.getString(normalized, OAuthParams.HMAC_SHA1, credentials.secret!!, credentials.consumerSecret!!)
val oauthHeaders = linkedMapOf<String, String>()
if (credentials.consumerKey != null) {
oauthHeaders[OAuthParams.OAUTH_CONSUMER_KEY] = quoted(credentials.consumerKey!!)
}
oauthHeaders[OAuthParams.OAUTH_NONCE] = quoted(nonce)
oauthHeaders[OAuthParams.OAUTH_SIGNATURE] = quoted(signature)
oauthHeaders[OAuthParams.OAUTH_SIGNATURE_METHOD] = quoted(OAuthParams.HMAC_SHA1)
oauthHeaders[OAuthParams.OAUTH_TIMESTAMP] = quoted(java.lang.Long.toString(timestampSecs))
if (credentials.token != null) {
oauthHeaders[OAuthParams.OAUTH_TOKEN] = quoted(credentials.token!!)
}
oauthHeaders[OAuthParams.OAUTH_VERSION] = quoted(OAuthParams.ONE_DOT_OH)
return "OAuth " + oauthHeaders.entries.joinToString(", ") { it.key + "=" + it.value }
}
private fun isFormContentType(request: Request): Boolean {
return request.body!!.contentType()!!.toString().startsWith(
"application/x-www-form-urlencoded"
)
}
companion object {
private val log = Logger.getLogger(TwitterAuthInterceptor::class.java.name)
}
}