Add (un)registration features

This commit is contained in:
S1m 2021-11-23 01:05:36 +01:00
parent 993ffaf8f9
commit 0ed93a9228
7 changed files with 198 additions and 89 deletions

View File

@ -16,6 +16,7 @@ private const val TAG = "AccountUtils"
const val PREF_NAME = "NextPush"
const val PREF_DEVICE_ID = "deviceId"
const val PREF_URL = "url"
lateinit var ssoAccount: SingleSignOnAccount
@ -59,3 +60,22 @@ fun removeDeviceId(context: Context) {
.remove(PREF_DEVICE_ID)
.commit()
}
fun saveUrl(context: Context, url: String) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.putString(PREF_URL, url)
.commit()
}
fun getUrl(context: Context) : String? {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.getString(PREF_URL,null)
}
fun removeUrl(context: Context) {
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
.edit()
.remove(PREF_URL)
.commit()
}

View File

@ -33,7 +33,7 @@ import org.unifiedpush.distributor.nextpush.distributor.sendUnregistered
import org.unifiedpush.distributor.nextpush.distributor.MessagingDatabase
import java.lang.String.format
const val TAG = "NextPush-MainActivity"
private const val TAG = "NextPush-MainActivity"
class MainActivity : AppCompatActivity() {
@ -203,10 +203,15 @@ class MainActivity : AppCompatActivity() {
alert.setTitle("Unregistering")
alert.setMessage("Are you sure to unregister ${appList[position]} ?")
alert.setPositiveButton("YES") { dialog, _ ->
sendUnregistered(this, tokenList[position])
val connectorToken = tokenList[position]
sendUnregistered(this, connectorToken)
val db = MessagingDatabase(this)
db.unregisterApp(tokenList[position])
val appToken = db.getAppToken(connectorToken)
db.unregisterApp(connectorToken)
db.close()
ApiUtils().deleteApp(this, appToken) {
Log.d(TAG,"Unregistration is finished")
}
tokenList.removeAt(position)
appList.removeAt(position)
dialog.dismiss()

View File

@ -40,7 +40,7 @@ class SettingsActivity : AppCompatActivity() {
val tokenList = db.listTokens()
db.close()
tokenList.forEach {
sendEndpoint(this, it, getEndpoint(this, it))
sendEndpoint(this, it)
}
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)

View File

@ -12,11 +12,9 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.sse.EventSource
import okhttp3.sse.EventSources
import org.unifiedpush.distributor.nextpush.account.getDeviceId
import org.unifiedpush.distributor.nextpush.account.removeDeviceId
import org.unifiedpush.distributor.nextpush.account.saveDeviceId
import org.unifiedpush.distributor.nextpush.account.ssoAccount
import org.unifiedpush.distributor.nextpush.account.*
import org.unifiedpush.distributor.nextpush.api.ProviderApi.Companion.mApiEndpoint
import org.unifiedpush.distributor.nextpush.distributor.MessagingDatabase
import org.unifiedpush.distributor.nextpush.services.SSEListener
import retrofit2.NextcloudRetrofitApiBuilder
import java.util.concurrent.TimeUnit
@ -83,6 +81,7 @@ class ApiUtils {
}
override fun onComplete() {
saveUrl(context, "${ssoAccount.url}${mApiEndpoint}")
// Sync once it is registered
cSync(deviceId!!)
Log.d(TAG, "mApi register: onComplete")
@ -131,7 +130,7 @@ class ApiUtils {
if (response.success) {
Log.d(TAG, "Device successfully deleted.")
} else {
Log.d(TAG, "An error occurred while deleting the device registration.")
Log.d(TAG, "An error occurred while deleting the device.")
}
}
@ -140,24 +139,98 @@ class ApiUtils {
}
override fun onComplete() {
removeUrl(context)
}
})
removeDeviceId(context)
}
fun createApp(context: Context) {
cApi(context) { cCreateApp(context) }
fun createApp(context: Context,
appName: String,
connectorToken: String,
callback: ()->Unit) {
cApi(context) {
cCreateApp(context, appName, connectorToken) {
callback()
}
}
}
private fun cCreateApp(context: Context) {
private fun cCreateApp(context: Context,
appName: String,
connectorToken: String,
callback: ()->Unit) {
val db = MessagingDatabase(context)
if (db.isRegistered(appName, connectorToken)) {
Log.i("RegisterService","$appName already registered")
db.close()
callback()
return
}
val parameters = mutableMapOf(
"deviceId" to getDeviceId(context)!!,
"appName" to appName
)
mApi.createApp(parameters)
?.subscribeOn(Schedulers.newThread())
?.observeOn(Schedulers.newThread())
?.subscribe(object : Observer<ApiResponse?> {
override fun onSubscribe(d: Disposable) {
Log.d(TAG, "Subscribed to createApp.")
}
override fun onNext(response: ApiResponse) {
if (response.success) {
Log.d(TAG, "App successfully created.")
db.registerApp(appName, connectorToken, response.token)
} else {
Log.d(TAG, "An error occurred while creating the application.")
}
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
db.close()
callback()
}
})
}
fun deleteApp(context: Context) {
cApi(context) { cDeleteApp(context) }
fun deleteApp(context: Context, appToken: String, callback: ()->Unit) {
cApi(context) {
cDeleteApp(appToken) {
callback()
}
}
}
private fun cDeleteApp(context: Context) {
private fun cDeleteApp(appToken: String, callback: ()->Unit) {
mApi.deleteApp(appToken)
?.subscribeOn(Schedulers.newThread())
?.observeOn(Schedulers.newThread())
?.subscribe(object : Observer<ApiResponse?> {
override fun onSubscribe(d: Disposable) {
Log.d(TAG, "Subscribed to deleteApp.")
}
override fun onNext(response: ApiResponse) {
if (response.success) {
Log.d(TAG, "App successfully deleted.")
} else {
Log.d(TAG, "An error occurred while deleting the application.")
}
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
callback()
}
})
}
}

View File

@ -3,11 +3,14 @@ package org.unifiedpush.distributor.nextpush.distributor
import android.content.Context
import android.content.Intent
import android.util.Log
import org.unifiedpush.distributor.nextpush.account.getUrl
/**
* These functions are used to send messages to other apps
*/
private const val TAG = "DistributorUtils"
fun sendMessage(context: Context, token: String, message: String){
val application = getApp(context, token)
if (application.isNullOrBlank()) {
@ -21,46 +24,46 @@ fun sendMessage(context: Context, token: String, message: String){
context.sendBroadcast(broadcastIntent)
}
fun sendEndpoint(context: Context, token: String, endpoint: String) {
val application = getApp(context, token)
fun sendEndpoint(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_NEW_ENDPOINT
broadcastIntent.putExtra(EXTRA_TOKEN, token)
broadcastIntent.putExtra(EXTRA_ENDPOINT, endpoint)
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
broadcastIntent.putExtra(EXTRA_ENDPOINT, getEndpoint(context, connectorToken))
context.sendBroadcast(broadcastIntent)
}
fun sendUnregistered(context: Context, token: String) {
val application = getApp(context, token)
fun sendUnregistered(context: Context, connectorToken: String) {
val application = getApp(context, connectorToken)
if (application.isNullOrBlank()) {
return
}
val broadcastIntent = Intent()
broadcastIntent.`package` = application
broadcastIntent.action = ACTION_UNREGISTERED
broadcastIntent.putExtra(EXTRA_TOKEN, token)
broadcastIntent.putExtra(EXTRA_TOKEN, connectorToken)
context.sendBroadcast(broadcastIntent)
}
fun getApp(context: Context, token: String): String?{
fun getApp(context: Context, connectorToken: String): String?{
val db = MessagingDatabase(context)
val app = db.getPackageName(token)
val app = db.getPackageName(connectorToken)
db.close()
return if (app.isBlank()) {
Log.w("notifyClient", "No app found for $token")
Log.w(TAG, "No app found for $connectorToken")
null
} else {
app
}
}
fun getEndpoint(context: Context, appToken: String): String {
val settings = context.getSharedPreferences("Config", Context.MODE_PRIVATE)
val address = settings?.getString("address","")
return settings?.getString("proxy","") +
"/foo/$appToken/"
fun getEndpoint(context: Context, connectorToken: String): String {
val db = MessagingDatabase(context)
val appToken = db.getAppToken(connectorToken)
db.close()
return "${getUrl(context)}/push/$appToken"
}

View File

@ -10,13 +10,16 @@ private const val DB_VERSION = 1
class MessagingDatabase(context: Context):
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
private val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
"package_name TEXT," +
"token TEXT," +
"PRIMARY KEY (token));"
private val TABLE_APPS = "apps"
private val FIELD_PACKAGE_NAME = "package_name"
private val FIELD_TOKEN = "token"
private val FIELD_PACKAGE_NAME = "packageName"
private val FIELD_CONNECTOR_TOKEN = "connectorToken"
private val FIELD_APP_TOKEN = "appToken"
private val CREATE_TABLE_APPS = "CREATE TABLE apps (" +
"$FIELD_PACKAGE_NAME TEXT," +
"$FIELD_CONNECTOR_TOKEN TEXT," +
"$FIELD_APP_TOKEN TEXT," +
"PRIMARY KEY ($FIELD_CONNECTOR_TOKEN));"
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(CREATE_TABLE_APPS)
@ -26,26 +29,27 @@ class MessagingDatabase(context: Context):
throw IllegalStateException("Upgrades not supported")
}
fun registerApp(packageName: String, token: String) {
fun registerApp(packageName: String, connectorToken: String, appToken: String) {
val db = writableDatabase
val values = ContentValues().apply {
put(FIELD_PACKAGE_NAME, packageName)
put(FIELD_TOKEN, token)
put(FIELD_CONNECTOR_TOKEN, connectorToken)
put(FIELD_APP_TOKEN, appToken)
}
db.insert(TABLE_APPS, null, values)
}
fun unregisterApp(token: String) {
fun unregisterApp(connectorToken: String) {
val db = writableDatabase
val selection = "$FIELD_TOKEN = ?"
val selectionArgs = arrayOf(token)
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
val selectionArgs = arrayOf(connectorToken)
db.delete(TABLE_APPS, selection, selectionArgs)
}
fun isRegistered(packageName: String, token: String): Boolean {
fun isRegistered(packageName: String, connectorToken: String): Boolean {
val db = readableDatabase
val selection = "$FIELD_PACKAGE_NAME = ? AND $FIELD_TOKEN = ?"
val selectionArgs = arrayOf(packageName, token)
val selection = "$FIELD_PACKAGE_NAME = ? AND $FIELD_CONNECTOR_TOKEN = ?"
val selectionArgs = arrayOf(packageName, connectorToken)
return db.query(
TABLE_APPS,
null,
@ -59,11 +63,11 @@ class MessagingDatabase(context: Context):
}
}
fun getPackageName(token: String): String {
fun getPackageName(connectorToken: String): String {
val db = readableDatabase
val projection = arrayOf(FIELD_PACKAGE_NAME)
val selection = "$FIELD_TOKEN = ?"
val selectionArgs = arrayOf(token)
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
val selectionArgs = arrayOf(connectorToken)
return db.query(
TABLE_APPS,
projection,
@ -78,9 +82,28 @@ class MessagingDatabase(context: Context):
}
}
fun getAppToken(connectorToken: String): String {
val db = readableDatabase
val projection = arrayOf(FIELD_APP_TOKEN)
val selection = "$FIELD_CONNECTOR_TOKEN = ?"
val selectionArgs = arrayOf(connectorToken)
return db.query(
TABLE_APPS,
projection,
selection,
selectionArgs,
null,
null,
null
).use { cursor ->
val column = cursor.getColumnIndex(FIELD_APP_TOKEN)
if (cursor.moveToFirst() && column >= 0) cursor.getString(column) else ""
}
}
fun listTokens(): List<String> {
val db = readableDatabase
val projection = arrayOf(FIELD_TOKEN)
val projection = arrayOf(FIELD_CONNECTOR_TOKEN)
return db.query(
TABLE_APPS,
projection,
@ -92,7 +115,7 @@ class MessagingDatabase(context: Context):
).use{ cursor ->
generateSequence { if (cursor.moveToNext()) cursor else null }
.mapNotNull{
val column = cursor.getColumnIndex(FIELD_TOKEN)
val column = cursor.getColumnIndex(FIELD_CONNECTOR_TOKEN)
if (column >= 0) it.getString(column) else null }
.toList()
}

View File

@ -5,60 +5,45 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import org.unifiedpush.distributor.nextpush.distributor.*
import kotlin.concurrent.thread
import org.unifiedpush.distributor.nextpush.api.ApiUtils
/**
* THIS SERVICE IS USED BY OTHER APPS TO REGISTER
*/
private const val TAG = "RegisterBroadcastReceiver"
class RegisterBroadcastReceiver : BroadcastReceiver() {
private fun unregisterApp(db: MessagingDatabase, application: String, token: String) {
Log.i("RegisterService","Unregistering $application token: $token")
db.unregisterApp(token)
}
private fun registerApp(context: Context?, db: MessagingDatabase, application: String, token: String) {
if (application.isBlank()) {
Log.w("RegisterService","Trying to register an app without packageName")
return
}
Log.i("RegisterService","registering $application token: $token")
// The app is registered with the same token : we re-register it
// the client may need its endpoint again
if (db.isRegistered(application, token)) {
Log.i("RegisterService","$application already registered")
return
}
db.registerApp(application, token)
}
override fun onReceive(context: Context?, intent: Intent?) {
when (intent!!.action) {
ACTION_REGISTER ->{
Log.i("Register","REGISTER")
val token = intent.getStringExtra(EXTRA_TOKEN)?: ""
Log.i(TAG,"REGISTER")
val connectorToken = intent.getStringExtra(EXTRA_TOKEN)?: ""
val application = intent.getStringExtra(EXTRA_APPLICATION)?: ""
thread(start = true) {
val db = MessagingDatabase(context!!)
registerApp(context, db, application, token)
db.close()
Log.i("RegisterService","Registration is finished")
}.join()
sendEndpoint(context!!, token, getEndpoint(context, token))
if (application.isBlank()) {
Log.w(TAG,"Trying to register an app without packageName")
return
}
ApiUtils().createApp(context!!.applicationContext, application, connectorToken) {
sendEndpoint(context.applicationContext, connectorToken)
}
}
ACTION_UNREGISTER ->{
Log.i("Register","UNREGISTER")
val token = intent.getStringExtra(EXTRA_TOKEN)?: ""
val application = intent.getStringExtra(EXTRA_APPLICATION)?: ""
thread(start = true) {
val db = MessagingDatabase(context!!)
unregisterApp(db,application, token)
db.close()
Log.i("RegisterService","Unregistration is finished")
Log.i(TAG,"UNREGISTER")
val connectorToken = intent.getStringExtra(EXTRA_TOKEN)?: ""
val application = intent.getStringExtra(EXTRA_APPLICATION)?: return
if (application.isBlank()) {
return
}
sendUnregistered(context!!.applicationContext, connectorToken)
val db = MessagingDatabase(context.applicationContext)
val appToken = db.getAppToken(connectorToken)
db.unregisterApp(connectorToken)
db.close()
ApiUtils().deleteApp(context.applicationContext, appToken) {
Log.d(TAG,"Unregistration is finished")
}
sendUnregistered(context!!, token)
}
}
}