peertube-live-streaming/app/src/main/java/fr/mobdev/peertubelive/manager/OAuthManager.kt

532 lines
21 KiB
Kotlin

package fr.mobdev.peertubelive.manager
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import fr.mobdev.peertubelive.BuildConfig
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.objects.OAuthData
import org.json.JSONObject
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.net.UnknownHostException
import java.util.*
import java.util.concurrent.Semaphore
import kotlin.collections.ArrayList
class OAuthManager {
constructor() {
start()
}
fun register(context: Context, url: String, listener: InstanceManager.InstanceListener) {
val args = Bundle()
args.putString(URL, url)
val message = Message()
message.type = Message.Message_Type.REGISTER
message.context = context
message.args = args
message.listener = listener
addMessage(message)
}
fun getUserToken(context: Context, url: String, username: String, password: String, oauthData: OAuthData, listener: InstanceManager.InstanceListener) {
val args = Bundle()
args.putString(URL, url)
args.putParcelable(OAUTH_DATA, oauthData)
args.putString(USERNAME, username)
args.putString(PASSWORD, password)
val message = Message()
message.type = Message.Message_Type.GET_USER_TOKEN
message.context = context
message.args = args
message.listener = listener
addMessage(message)
}
fun refreshToken(context: Context, url: String, oauthData: OAuthData, listener: InstanceManager.InstanceListener) {
val args = Bundle()
args.putString(URL, url)
args.putParcelable(OAUTH_DATA, oauthData)
val message = Message()
message.type = Message.Message_Type.REFRESH_TOKEN
message.context = context
message.args = args
message.listener = listener
addMessage(message)
}
fun post(context: Context, url: String, oauthData: OAuthData, data: Bundle, listener: InstanceManager.InstanceListener) {
val args = Bundle()
args.putString(URL, url)
args.putParcelable(OAUTH_DATA, oauthData)
args.putBundle(DATA, data)
val message = Message()
message.type = Message.Message_Type.POST
message.context = context
message.args = args
message.listener = listener
addMessage(message)
}
fun get(context: Context, url: String, oauthData: OAuthData?, listener: InstanceManager.InstanceListener) {
val args = Bundle()
args.putString(URL, url)
args.putParcelable(OAUTH_DATA, oauthData)
val message = Message()
message.type = Message.Message_Type.GET
message.context = context
message.args = args
message.listener = listener
addMessage(message)
}
private companion object OAuthThread : Thread() {
private val messageQueue: ArrayList<Message> = ArrayList()
private val sem: Semaphore = Semaphore(0, true)
private const val URL: String = "URL"
private const val USERNAME: String = "USERNAME"
private const val PASSWORD: String = "PASSWORD"
private const val OAUTH_DATA: String = "OAUTH_DATA"
private const val DATA: String = "DATA"
private const val EXTRA_DATA: String = "EXTRA_DATA"
private const val CONTENT_TYPE: String = "CONTENT_TYPE"
private const val CONTENT_DATA: String = "CONTENT_DATA"
fun addMessage(message: Message)
{
messageQueue.add(message)
sem.release()
}
override fun run() {
var isRunning = true
while (isRunning) {
try {
sem.acquire()
val mes: Message = messageQueue.removeAt(0)
when (mes.type) {
Message.Message_Type.REGISTER -> register(mes)
Message.Message_Type.GET_USER_TOKEN -> getUserToken(mes)
Message.Message_Type.REFRESH_TOKEN -> refreshToken(mes)
Message.Message_Type.POST -> post(mes)
Message.Message_Type.GET -> get(mes)
else -> {}
}
} catch (e: InterruptedException) {
isRunning = false
}
}
}
fun register(message: Message) {
if (!isConnectedToInternet(message.context)) {
message.listener?.onError(message.context.getString(R.string.network_error))
return
}
val url: String = message.args.getString(URL,"")
val registerUrl = URL(url)
val connection: HttpURLConnection = registerUrl.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.setRequestProperty("User-Agent", "Peeriscope")
connection.setRequestProperty("Content-Type", "application/json")
connection.setRequestProperty("Accept", "application/json")
connection.doInput = true
var inputStream: InputStream
var inError = false
try {
inputStream = connection.inputStream
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e : Exception) {
e.printStackTrace()
inputStream = connection.errorStream
inError = true
}
val response = readInputStream(inputStream)
if(!inError) {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val clientId = rootObj.getString("client_id")
val clientSecret = rootObj.getString("client_secret")
val oauthData = OAuthData(null, null, clientId, clientSecret, null, null, 0, null,0)
val result = Bundle()
result.putParcelable(EXTRA_DATA, oauthData)
message.listener?.onSuccess(result)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
} else {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val error = rootObj.getString("error")
message.listener?.onError(error)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
}
}
fun getUserToken(message: Message) {
if (!isConnectedToInternet(message.context)) {
message.listener?.onError(message.context.getString(R.string.network_error))
return
}
val url: String = message.args.getString(URL, "")
val getUserTokenUrl = URL(url)
val connection: HttpURLConnection = getUserTokenUrl.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("User-Agent", "Peeriscope")
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
connection.setRequestProperty("Accept", "application/json")
connection.doInput = true
connection.doOutput = true
val oauth: OAuthData? = message.args.getParcelable(OAUTH_DATA)
if (BuildConfig.DEBUG && oauth == null) {
error("Missing OAUTH DATA")
}
val username: String = message.args.getString(USERNAME,"")
val password: String = message.args.getString(PASSWORD,"")
var output = ""
output += "client_id=" + (oauth?.clientId ?: "")
output += "&client_secret=" + (oauth?.clientSecret ?: "")
output += "&grant_type=password"
output += "&response_type=code"
output += "&username=$username"
output += "&password=$password"
val outputStream = connection.outputStream
outputStream.write(output.toByteArray())
var inputStream: InputStream
var inError = false
try {
inputStream = connection.inputStream
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e : Exception) {
e.printStackTrace()
inputStream = connection.errorStream
inError = true
}
val response = readInputStream(inputStream)
if(!inError) {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val accessToken = rootObj.getString("access_token")
val tokenType = rootObj.getString("token_type")
var expires = Calendar.getInstance().timeInMillis
expires += rootObj.getLong("expires_in")*1000
val refreshToken = rootObj.getString("refresh_token")
var refreshTokenExpires = Calendar.getInstance().timeInMillis
refreshTokenExpires += rootObj.getLong("refresh_token_expires_in")*1000
val oauthData = OAuthData(oauth?.baseUrl,username,oauth?.clientId, oauth?.clientSecret, accessToken, tokenType, expires, refreshToken, refreshTokenExpires)
val result = Bundle()
result.putParcelable(EXTRA_DATA, oauthData)
message.listener?.onSuccess(result)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
} else {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val error = rootObj.getString("error")
message.listener?.onError(error)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
}
}
fun refreshToken(message: Message) {
if (!isConnectedToInternet(message.context)) {
message.listener?.onError(message.context.getString(R.string.network_error))
return
}
val url: String = message.args.getString(URL, "")
val getUserTokenUrl = URL(url)
val connection: HttpURLConnection = getUserTokenUrl.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("User-Agent", "Peeriscope")
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
connection.setRequestProperty("Accept", "application/json")
connection.doInput = true
connection.doOutput = true
val oauth: OAuthData? = message.args.getParcelable(OAUTH_DATA)
if (BuildConfig.DEBUG && oauth == null) {
error("Missing OAUTH DATA")
}
var output = ""
output += "client_id=" + (oauth?.clientId ?: "")
output += "&client_secret=" + (oauth?.clientSecret ?: "")
output += "&grant_type=refresh_token"
output += "&response_type=code"
output += "&refresh_token=" +(oauth?.refreshToken?: "")
val outputStream = connection.outputStream
outputStream.write(output.toByteArray())
var inputStream: InputStream
var inError = false
try {
inputStream = connection.inputStream
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e : Exception) {
e.printStackTrace()
inputStream = connection.errorStream
inError = true
}
val response = readInputStream(inputStream)
if(!inError) {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val accessToken = rootObj.getString("access_token")
val tokenType = rootObj.getString("token_type")
var expires = Calendar.getInstance().timeInMillis
expires += rootObj.getLong("expires_in")*1000
val refreshToken = rootObj.getString("refresh_token")
var refreshTokenExpires = Calendar.getInstance().timeInMillis
refreshTokenExpires += rootObj.getLong("refresh_token_expires_in")*1000
val oauthData = OAuthData(oauth?.baseUrl,oauth?.username,oauth?.clientId, oauth?.clientSecret, accessToken, tokenType, expires, refreshToken, refreshTokenExpires)
val result = Bundle()
result.putParcelable(EXTRA_DATA, oauthData)
message.listener?.onSuccess(result)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
} else {
if(response.isNotEmpty()) {
val rootObj = JSONObject(response)
val error = rootObj.getString("error")
message.listener?.onError(error)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
}
}
fun post(message: Message) {
if (!isConnectedToInternet(message.context)) {
message.listener?.onError(message.context.getString(R.string.network_error))
return
}
val url: String = message.args.getString(URL, "")
val postUrl = URL(url)
val data = message.args.getBundle(DATA)!!
val connection: HttpURLConnection = postUrl.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("User-Agent", "Peeriscope")
connection.setRequestProperty("Content-Type", data.getString(CONTENT_TYPE,"application/json"))
connection.setRequestProperty("Accept", "application/json")
connection.doInput = true
connection.doOutput = true
val oauth: OAuthData? = message.args.getParcelable(OAUTH_DATA)
if (BuildConfig.DEBUG && oauth == null) {
error("Missing OAUTH DATA")
}
val extraData: String = data.getString(CONTENT_DATA,"")
connection.setRequestProperty("Authorization","Bearer ${oauth?.accessToken}")
var inputStream: InputStream? = null
val outputStream: OutputStream
var inError = false
try {
outputStream = connection.outputStream
outputStream.write(extraData.toByteArray())
outputStream.flush()
outputStream.close()
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e : Exception) {
e.printStackTrace()
inError = true
inputStream = connection.errorStream
}
if(!inError) {
try {
inputStream = connection.inputStream
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e: Exception) {
e.printStackTrace()
inputStream = connection.errorStream
inError = true
}
}
if (inputStream != null) {
val response = readInputStream(inputStream)
if (!inError) {
if (response.isNotEmpty()) {
val result = Bundle()
result.putString(EXTRA_DATA, response)
message.listener?.onSuccess(result)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
} else {
if (response.isNotEmpty()) {
try {
val rootObj = JSONObject(response)
val error = rootObj.getString("error")
message.listener?.onError(error)
} catch (e: Exception) {
message.listener?.onError(message.context.getString(R.string.json_error))
}
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
}
}
}
fun get(message: Message) {
if (!isConnectedToInternet(message.context)) {
message.listener?.onError(message.context.getString(R.string.network_error))
return
}
val url: String = message.args.getString(URL, "")
val getUserTokenUrl = URL(url)
val connection: HttpURLConnection = getUserTokenUrl.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.setRequestProperty("User-Agent", "Peeriscope")
connection.setRequestProperty("Content-Type", "application/json")
connection.setRequestProperty("Accept", "application/json")
connection.doInput = true
val oauth: OAuthData? = message.args.getParcelable(OAUTH_DATA)
if (oauth != null) {
connection.setRequestProperty("Authorization", "Bearer ${oauth.accessToken}")
}
var inputStream: InputStream
var inError = false
try {
inputStream = connection.inputStream
} catch (e: UnknownHostException) {
message.listener?.onError(message.context.getString(R.string.unknown_host))
return
} catch (e : Exception) {
e.printStackTrace()
inputStream = connection.errorStream
inError = true
}
val response = readInputStream(inputStream)
if(!inError) {
if(response.isNotEmpty()) {
val result = Bundle()
result.putString(EXTRA_DATA, response)
message.listener?.onSuccess(result)
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
} else {
if(response.isNotEmpty()) {
try {
val rootObj = JSONObject(response)
val error = rootObj.getString("error")
message.listener?.onError(error)
} catch (e: Exception) {
message.listener?.onError(message.context.getString(R.string.json_error))
}
} else {
message.listener?.onError(message.context.getString(R.string.unknwon_error))
}
}
}
fun readInputStream(inputStream: InputStream) : String {
val inReader = InputStreamReader(inputStream)
val bufReader = BufferedReader(inReader)
var line: String?
var response = ""
do {
line = bufReader.readLine()
if(line != null)
response += line
}while (line != null)
return response
}
private fun isConnectedToInternet(context: Context): Boolean {
//verify the connectivity
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
if(capabilities != null)
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) || capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
} else {
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null)
return networkInfo.isConnected
}
return false
}
}
private class Message {
var type: Message_Type = Message_Type.UNKNOWN
var args = Bundle()
var listener: InstanceManager.InstanceListener? = null
lateinit var context: Context
enum class Message_Type {
REGISTER, GET_USER_TOKEN, REFRESH_TOKEN, POST, GET, UNKNOWN
}
}
}