From fc4c9139c5a11998666113408f455860b13e7f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Tue, 20 Oct 2020 11:23:50 +0200 Subject: [PATCH] Add support for token-based authentication. --- .../minicards/ConfigManager.java | 14 ++++++++ .../bridge/ProgramakerAndroidBridge.java | 10 +++--- .../bridge/ProgramakerBridgeService.java | 12 ++++++- .../com/programaker/api/ProgramakerApi.kt | 32 +++++++++++++++++-- .../api_results/ProgramakerFullBridgeInfo.kt | 6 ++++ .../programaker/bridge/ProgramakerBridge.kt | 11 +++++++ 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/programaker/api/data/api_results/ProgramakerFullBridgeInfo.kt diff --git a/app/src/main/java/com/codigoparallevar/minicards/ConfigManager.java b/app/src/main/java/com/codigoparallevar/minicards/ConfigManager.java index 825dc5d..ba59713 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/ConfigManager.java +++ b/app/src/main/java/com/codigoparallevar/minicards/ConfigManager.java @@ -10,6 +10,7 @@ public class ConfigManager { private static final String PREFERENCES_NAME = "MINICARDS_PREFERENCES"; private static final String TOKEN_KEY = "PROGRAMAKER_API_TOKEN"; private static final String BRIDGE_ID_KEY = "PROGRAMAKER_BRIDGE_ID"; + private static final String BRIDGE_AUTHENTICATION_TOKEN_KEY = "BRIDGE_AUTHENTICATION_TOKEN"; private static final String BRIDGE_CONNECTION_ID_KEY = "PROGRAMAKER_BRIDGE_CONNECTION_ID"; public ConfigManager(Context ctx) { @@ -63,4 +64,17 @@ public class ConfigManager { SharedPreferences preferences = this.context.getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE); return preferences.getString(BRIDGE_CONNECTION_ID_KEY, null); } + + public void setBridgeAuthenticationToken(String bridgeAuthToken) { + SharedPreferences preferences = this.context.getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE); + SharedPreferences.Editor edit = preferences.edit(); + + edit.putString(BRIDGE_AUTHENTICATION_TOKEN_KEY, bridgeAuthToken); + edit.commit(); + } + + public String getBridgeAuthenticationToken() { + SharedPreferences preferences = this.context.getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE); + return preferences.getString(BRIDGE_AUTHENTICATION_TOKEN_KEY, null); + } } diff --git a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerAndroidBridge.java b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerAndroidBridge.java index d5eb0bd..46b3b92 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerAndroidBridge.java +++ b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerAndroidBridge.java @@ -15,8 +15,8 @@ public class ProgramakerAndroidBridge { private StatusStreamer statusStreamer = null; // Static - public static ProgramakerAndroidBridge configure(Context ctx, String userId, String bridgeId) { - return new ProgramakerAndroidBridge(ctx, userId, bridgeId); + public static ProgramakerAndroidBridge configure(Context ctx, String userId, String bridgeId, String bridgeToken) { + return new ProgramakerAndroidBridge(ctx, userId, bridgeId, bridgeToken); } public static String GetBridgeName(Context ctx) { @@ -29,11 +29,13 @@ public class ProgramakerAndroidBridge { private final Context ctx; private final String userId; private final String bridgeId; + private final String bridgeToken; - private ProgramakerAndroidBridge(Context ctx, String userId, String bridgeId) { + private ProgramakerAndroidBridge(Context ctx, String userId, String bridgeId, String bridgeToken) { this.ctx = ctx; this.userId = userId; this.bridgeId = bridgeId; + this.bridgeToken = bridgeToken; } public void start(Runnable onReady, Runnable onComplete) { @@ -43,7 +45,7 @@ public class ProgramakerAndroidBridge { DefaultAndroidBlocks.GetBuilder(this.ctx).Build() ); - this.bridgeRunner = new ProgramakerBridge(this.bridgeId, this.userId, configuration, onReady, onComplete); + this.bridgeRunner = new ProgramakerBridge(this.bridgeId, this.userId, this.bridgeToken, configuration, onReady, onComplete); this.bridgeRunner.run(); this.statusStreamer = new StatusStreamer(this.ctx, this.bridgeRunner); diff --git a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java index 7234f23..8921d90 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java +++ b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java @@ -30,6 +30,7 @@ enum ServiceState { public class ProgramakerBridgeService extends Service { public static final String BridgeUserNotificationChannel = "PROGRAMAKER_BRIDGE_USER_NOTIFICATION"; public static final CharSequence BridgeUserNotificationChannelName = "User notifications"; + private static final String AUTOGENERATED_TOKEN_NAME = "Auto-generated"; public static String BridgeUserVibrationNotificationChannel = "PROGRAMAKER_BRIDGE_USER_VIBRATION_NOTIFICATIONS"; public static CharSequence BridgeUserVibrationNotificationChannelName = "User-triggered vibration"; @@ -160,12 +161,21 @@ public class ProgramakerBridgeService extends Service { bridgeIdCheck = api.createBridge(ProgramakerAndroidBridge.GetBridgeName(this)); config.setBridgeId(bridgeIdCheck); } + + String bridgeAuthCheck = config.getBridgeAuthenticationToken(); + if (bridgeAuthCheck == null) { + bridgeAuthCheck = api.createBridgeAuthenticationToken(bridgeIdCheck, ProgramakerBridgeService.AUTOGENERATED_TOKEN_NAME); + config.setBridgeAuthenticationToken(bridgeAuthCheck); + } + final String bridgeId = bridgeIdCheck; + final String bridgeAuth = bridgeAuthCheck; ProgramakerBridgeService.this.bridge = ProgramakerAndroidBridge.configure( this, userId, - bridgeId); + bridgeId, + bridgeAuth); ProgramakerBridgeService.this.bridge.start( () -> { // On ready setBridgeStatusNotification(getString(R.string.bridge_service_online), ServiceState.RUNNING, null); diff --git a/app/src/main/java/com/programaker/api/ProgramakerApi.kt b/app/src/main/java/com/programaker/api/ProgramakerApi.kt index 4780e2f..b8703fa 100644 --- a/app/src/main/java/com/programaker/api/ProgramakerApi.kt +++ b/app/src/main/java/com/programaker/api/ProgramakerApi.kt @@ -211,6 +211,29 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") return result.getBridgeId() } + + fun createBridgeAuthenticationToken(bridgeId: String, tokenName: String): String { + val conn = URL(getCreateBridgeAuthenticationTokenUrl(bridgeId)).openConnection() as HttpURLConnection + conn.setRequestProperty("Content-Type", "application/json") + addAuthHeader(conn) + + conn.requestMethod = "POST"; + conn.doOutput = true; + + val postData = JSONObject(hashMapOf( + "name" to tokenName + ) as Map<*, *>) + + val wr = DataOutputStream(conn.outputStream) + wr.writeBytes(postData.toString()); + wr.flush(); + wr.close(); + + val result: ProgramakerFullBridgeInfo + result = parseJson(conn.inputStream, ProgramakerFullBridgeInfo::class.java) + return result.key + } + fun establishConnection(bridgeId: String): Boolean { // NOTE: This establishes a connection to a bridge as long as it can be done without interaction @@ -292,9 +315,14 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") return "$ApiRoot/v0/users/$userName/bridges" } + private fun getCreateBridgeAuthenticationTokenUrl(bridgeId: String): String { + this.withUserId() + return "$ApiRoot/v0/bridges/by-id/$bridgeId/tokens" + } + private fun getPrepareConnectionUrl(bridgeId: String): String { - this.withUserName() - return "$ApiRoot/v0/users/$userName/services/id/$bridgeId/how-to-enable" + this.withUserId() + return "$ApiRoot/v0/services/by-id/$bridgeId/how-to-enable" } private fun getEstablishConnectionUrl(bridgeId: String): String { diff --git a/app/src/main/java/com/programaker/api/data/api_results/ProgramakerFullBridgeInfo.kt b/app/src/main/java/com/programaker/api/data/api_results/ProgramakerFullBridgeInfo.kt new file mode 100644 index 0000000..5478344 --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/api_results/ProgramakerFullBridgeInfo.kt @@ -0,0 +1,6 @@ +package com.programaker.api.data.api_results + +class ProgramakerFullBridgeInfo ( + val key: String +) { +} diff --git a/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt b/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt index 417f9ba..e4e6f0f 100644 --- a/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt +++ b/app/src/main/java/com/programaker/bridge/ProgramakerBridge.kt @@ -14,6 +14,7 @@ import java.util.concurrent.TimeUnit class ProgramakerBridge( private val bridge_id: String, private val user_id: String, + private val bridge_token: String, private val config: ProgramakerBridgeConfiguration, private val onReady: Runnable, private val onComplete: Runnable @@ -49,6 +50,16 @@ class ProgramakerBridge( // Websocket management override fun onOpen(webSocket: WebSocket, response: Response) { this.webSocket = webSocket + + val auth = JSONObject(hashMapOf( + "type" to "AUTHENTICATION", + "value" to hashMapOf ( + "token" to this.bridge_token + ) + ) as Map<*, *>).toString() + + webSocket.send(auth) + webSocket.send(config.serialize()) onReady.run() }