in apps/chat-android/messaging-websocket/src/main/java/com/amazonaws/services/chime/sdk/messaging/utils/DefaultSigV4.kt [25:119]
override fun signURL(
method: String,
scheme: String,
serviceName: String,
hostname: String,
path: String,
payload: String,
queryParams: Map<String, List<String>>?
): String {
val now = getDateTimeString()
val today = getDateString(now)
val algorithm = "AWS4-HMAC-SHA256"
val signedHeaders = "host"
val canonicalHeaders = "host:${hostname.toLowerCase(Locale.getDefault())}\n"
val credentialScope = "$today/$region/$serviceName/aws4_request"
var params = mutableMapOf<String, MutableList<String>>().apply {
set("X-Amz-Algorithm", mutableListOf(algorithm))
set(
"X-Amz-Credential", mutableListOf(
encodeURIComponent("${credentials.accessKeyId}/$credentialScope")
)
)
set("X-Amz-Date", mutableListOf(now))
set("X-Amz-Expires", mutableListOf("10"))
set("X-Amz-SignedHeaders", mutableListOf("host"))
credentials.sessionToken?.let {
set("X-Amz-Security-Token", mutableListOf(encodeURIComponent(it)))
}
}
if (queryParams != null) {
for ((key, values) in queryParams) {
val encodedKey = encodeURIComponent(key)
values.sorted()
values.forEach {
if (!params.containsKey(encodedKey)) {
params[encodedKey] = mutableListOf()
}
params[encodedKey]?.add(encodeURIComponent(it))
}
}
}
val canonicalQueryStringBuilder = StringBuilder()
// Query string has to be sorted by parameters
params = params.toSortedMap()
params.forEach { (key, values) ->
values.forEach { value ->
if (canonicalQueryStringBuilder.isNotEmpty()) {
canonicalQueryStringBuilder.append("&")
}
canonicalQueryStringBuilder.append(key)
canonicalQueryStringBuilder.append("=")
canonicalQueryStringBuilder.append(value)
}
}
val canonicalQueryString = canonicalQueryStringBuilder.toString()
val canonicalRequest =
method +
"\n" +
path +
"\n" +
canonicalQueryString +
"\n" +
canonicalHeaders +
"\n" +
signedHeaders +
"\n" +
hex(sha256(payload))
val hashedCanonicalRequest = hex(sha256(canonicalRequest))
val stringToSign =
"AWS4-HMAC-SHA256\n" +
now +
"\n" +
today +
"/" +
region +
"/" +
serviceName +
"/aws4_request\n" +
hashedCanonicalRequest
val signingKey = getSignatureKey(credentials.secretAccessKey, today, region, serviceName)
val signature = hex(hmac(stringToSign, signingKey))
val finalParams = "$canonicalQueryString&X-Amz-Signature=$signature"
return "$scheme://$hostname$path?$finalParams"
}