Merge pull request #1026 from ceokot/sogs-auth

fix: Authenticate all Open Group API calls
This commit is contained in:
ThomasSession 2024-06-24 11:12:03 +10:00 committed by GitHub
commit 1619277b4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 65 deletions

View File

@ -37,6 +37,7 @@ class BackgroundGroupAddJob(val joinUrl: String): Job {
delegate?.handleJobFailed(this, dispatcherName, DuplicateGroupException())
return
}
storage.addOpenGroup(openGroup.joinUrl())
storage.onOpenGroupAdded(openGroup.server, openGroup.room)
} catch (e: Exception) {

View File

@ -273,7 +273,6 @@ object OpenGroupApi {
val queryParameters: Map<String, String> = mapOf(),
val parameters: Any? = null,
val headers: Map<String, String> = mapOf(),
val isAuthRequired: Boolean = true,
val body: ByteArray? = null,
/**
* Always `true` under normal circumstances. You might want to disable
@ -319,73 +318,72 @@ object OpenGroupApi {
?: return Promise.ofFail(Error.NoEd25519KeyPair)
val urlRequest = urlBuilder.toString()
val headers = request.headers.toMutableMap()
if (request.isAuthRequired) {
val nonce = sodium.nonce(16)
val timestamp = TimeUnit.MILLISECONDS.toSeconds(SnodeAPI.nowWithOffset)
var pubKey = ""
var signature = ByteArray(Sign.BYTES)
var bodyHash = ByteArray(0)
if (request.parameters != null) {
val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray()
val parameterHash = ByteArray(GenericHash.BYTES_MAX)
if (sodium.cryptoGenericHash(
parameterHash,
parameterHash.size,
parameterBytes,
parameterBytes.size.toLong()
)
) {
bodyHash = parameterHash
}
} else if (request.body != null) {
val byteHash = ByteArray(GenericHash.BYTES_MAX)
if (sodium.cryptoGenericHash(
byteHash,
byteHash.size,
request.body,
request.body.size.toLong()
)
) {
bodyHash = byteHash
}
}
val messageBytes = Hex.fromStringCondensed(publicKey)
.plus(nonce)
.plus("$timestamp".toByteArray(Charsets.US_ASCII))
.plus(request.verb.rawValue.toByteArray())
.plus("/${request.endpoint.value}".toByteArray())
.plus(bodyHash)
if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
pubKey = SessionId(
IdPrefix.BLINDED,
keyPair.publicKey.asBytes
).hexString
signature = SodiumUtilities.sogsSignature(
messageBytes,
ed25519KeyPair.secretKey.asBytes,
keyPair.secretKey.asBytes,
keyPair.publicKey.asBytes
) ?: return Promise.ofFail(Error.SigningFailed)
} ?: return Promise.ofFail(Error.SigningFailed)
} else {
pubKey = SessionId(
IdPrefix.UN_BLINDED,
ed25519KeyPair.publicKey.asBytes
).hexString
sodium.cryptoSignDetached(
signature,
messageBytes,
messageBytes.size.toLong(),
ed25519KeyPair.secretKey.asBytes
val nonce = sodium.nonce(16)
val timestamp = TimeUnit.MILLISECONDS.toSeconds(SnodeAPI.nowWithOffset)
var pubKey = ""
var signature = ByteArray(Sign.BYTES)
var bodyHash = ByteArray(0)
if (request.parameters != null) {
val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray()
val parameterHash = ByteArray(GenericHash.BYTES_MAX)
if (sodium.cryptoGenericHash(
parameterHash,
parameterHash.size,
parameterBytes,
parameterBytes.size.toLong()
)
) {
bodyHash = parameterHash
}
} else if (request.body != null) {
val byteHash = ByteArray(GenericHash.BYTES_MAX)
if (sodium.cryptoGenericHash(
byteHash,
byteHash.size,
request.body,
request.body.size.toLong()
)
) {
bodyHash = byteHash
}
headers["X-SOGS-Nonce"] = encodeBytes(nonce)
headers["X-SOGS-Timestamp"] = "$timestamp"
headers["X-SOGS-Pubkey"] = pubKey
headers["X-SOGS-Signature"] = encodeBytes(signature)
}
val messageBytes = Hex.fromStringCondensed(publicKey)
.plus(nonce)
.plus("$timestamp".toByteArray(Charsets.US_ASCII))
.plus(request.verb.rawValue.toByteArray())
.plus("/${request.endpoint.value}".toByteArray())
.plus(bodyHash)
if (serverCapabilities.isEmpty() || serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
SodiumUtilities.blindedKeyPair(publicKey, ed25519KeyPair)?.let { keyPair ->
pubKey = SessionId(
IdPrefix.BLINDED,
keyPair.publicKey.asBytes
).hexString
signature = SodiumUtilities.sogsSignature(
messageBytes,
ed25519KeyPair.secretKey.asBytes,
keyPair.secretKey.asBytes,
keyPair.publicKey.asBytes
) ?: return Promise.ofFail(Error.SigningFailed)
} ?: return Promise.ofFail(Error.SigningFailed)
} else {
pubKey = SessionId(
IdPrefix.UN_BLINDED,
ed25519KeyPair.publicKey.asBytes
).hexString
sodium.cryptoSignDetached(
signature,
messageBytes,
messageBytes.size.toLong(),
ed25519KeyPair.secretKey.asBytes
)
}
headers["X-SOGS-Nonce"] = encodeBytes(nonce)
headers["X-SOGS-Timestamp"] = "$timestamp"
headers["X-SOGS-Pubkey"] = pubKey
headers["X-SOGS-Signature"] = encodeBytes(signature)
val requestBuilder = okhttp3.Request.Builder()
.url(urlRequest)
@ -927,7 +925,7 @@ object OpenGroupApi {
}
fun getCapabilities(server: String): Promise<Capabilities, Exception> {
val request = Request(verb = GET, room = null, server = server, endpoint = Endpoint.Capabilities, isAuthRequired = false)
val request = Request(verb = GET, room = null, server = server, endpoint = Endpoint.Capabilities)
return getResponseBody(request).map { response ->
JsonUtil.fromJson(response, Capabilities::class.java)
}