cordova-plugin-sms-retriever
Advanced tools
| package com.andreszs.smsretriever; | ||
| import android.content.Context; | ||
| import android.content.ContextWrapper; | ||
| import android.content.pm.PackageManager; | ||
| import android.content.pm.Signature; | ||
| import android.util.Base64; | ||
| import android.util.Log; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.security.MessageDigest; | ||
| import java.security.NoSuchAlgorithmException; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| public class AppSignatureHashHelper extends ContextWrapper { | ||
| public static final String LOG_TAG = AppSignatureHashHelper.class.getSimpleName(); | ||
| private static final String HASH_TYPE = "SHA-256"; | ||
| private static final int NUM_HASHED_BYTES = 9; | ||
| private static final int NUM_BASE64_CHAR = 11; | ||
| public AppSignatureHashHelper(Context context) { | ||
| super(context); | ||
| } | ||
| /** | ||
| * Get all the app signatures for the current package | ||
| * https://github.com/googlesamples/android-credentials/blob/master/sms-verification/android/app/src/main/java/com/google/samples/smartlock/sms_verify/AppSignatureHelper.java | ||
| */ | ||
| public ArrayList<String> getAppSignatures() { | ||
| ArrayList<String> appCodes = new ArrayList<String>(); | ||
| try { | ||
| // Get all package signatures for the current package | ||
| String packageName = getPackageName(); | ||
| PackageManager packageManager = getPackageManager(); | ||
| Signature[] signatures = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures; | ||
| // For each signature create a compatible hash | ||
| for (Signature signature : signatures) { | ||
| String hash = hash(packageName, signature.toCharsString()); | ||
| if (hash != null) { | ||
| appCodes.add(String.format("%s", hash)); | ||
| } | ||
| } | ||
| } catch (PackageManager.NameNotFoundException e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| return appCodes; | ||
| } | ||
| private static String hash(String packageName, String signature) { | ||
| String appInfo = packageName + " " + signature; | ||
| try { | ||
| MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE); | ||
| messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8)); | ||
| byte[] hashSignature = messageDigest.digest(); | ||
| // truncated into NUM_HASHED_BYTES | ||
| hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES); | ||
| // encode into Base64 | ||
| String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP); | ||
| base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR); | ||
| return base64Hash; | ||
| } catch (NoSuchAlgorithmException e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| return null; | ||
| } | ||
| } |
| package com.andreszs.smsretriever; | ||
| import android.content.BroadcastReceiver; | ||
| import android.content.Context; | ||
| import android.content.Intent; | ||
| import android.os.Bundle; | ||
| import com.google.android.gms.auth.api.phone.SmsRetriever; | ||
| import com.google.android.gms.common.api.CommonStatusCodes; | ||
| import com.google.android.gms.common.api.Status; | ||
| /** | ||
| * BroadcastReceiver to wait for SMS messages. This can be registered either in the AndroidManifest or at runtime. Should filter Intents on SmsRetriever.SMS_RETRIEVED_ACTION. | ||
| */ | ||
| public class SMSBroadcastReceiver extends BroadcastReceiver { | ||
| private OTPReceiveListener otpListener; | ||
| public void setOTPListener(OTPReceiveListener otpListener) { | ||
| this.otpListener = otpListener; | ||
| } | ||
| @Override | ||
| public void onReceive(Context context, Intent intent) { | ||
| if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) { | ||
| Bundle extras = intent.getExtras(); | ||
| Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS); | ||
| if (status == null) { | ||
| return; | ||
| } | ||
| switch (status.getStatusCode()) { | ||
| case CommonStatusCodes.SUCCESS: | ||
| String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE); | ||
| if (otpListener != null) { | ||
| otpListener.onSmsReceived(message); | ||
| } | ||
| break; | ||
| case CommonStatusCodes.TIMEOUT: | ||
| // Waiting for SMS timed out (5 minutes) | ||
| if (otpListener != null) { | ||
| otpListener.onSmsReceiveTimeOut(); | ||
| } | ||
| break; | ||
| case CommonStatusCodes.API_NOT_CONNECTED: | ||
| if (otpListener != null) { | ||
| otpListener.onSmsReceivedError("API NOT CONNECTED"); | ||
| } | ||
| break; | ||
| case CommonStatusCodes.NETWORK_ERROR: | ||
| if (otpListener != null) { | ||
| otpListener.onSmsReceivedError("NETWORK ERROR"); | ||
| } | ||
| break; | ||
| case CommonStatusCodes.ERROR: | ||
| if (otpListener != null) { | ||
| otpListener.onSmsReceivedError("SOME THING WENT WRONG"); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * | ||
| */ | ||
| public interface OTPReceiveListener { | ||
| void onSmsReceived(String smsMessage); | ||
| void onSmsReceiveTimeOut(); | ||
| void onSmsReceivedError(String error); | ||
| } | ||
| } |
+1
-1
| { | ||
| "name": "cordova-plugin-sms-retriever", | ||
| "version": "2.0.1", | ||
| "version": "3.0.0", | ||
| "description": "Cordova plugin to retrieve SMS in Android using the SMS Retriever API.", | ||
@@ -5,0 +5,0 @@ "cordova": { |
+18
-6
@@ -6,3 +6,3 @@ <?xml version="1.0" encoding="utf-8"?> | ||
| id="cordova-plugin-sms-retriever" | ||
| version="2.0.1"> | ||
| version="3.0.0"> | ||
@@ -26,13 +26,23 @@ <name>SMS Retriever</name> | ||
| <platform name="android"> | ||
| <preference name="PLAY_SERVICES_AUTH_VERSION" default="20.5.0"/> | ||
| <preference name="PLAY_SERVICES_AUTH_API_PHONE_VERSION" default="18.0.1"/> | ||
| <framework src="com.google.android.gms:play-services-auth:$PLAY_SERVICES_AUTH_VERSION"/> | ||
| <framework src="com.google.android.gms:play-services-auth-api-phone:$PLAY_SERVICES_AUTH_API_PHONE_VERSION"/> | ||
| <preference name="PLAY_SERVICES_VERSION" default="15.0.0"/> | ||
| <framework src="com.google.android.gms:play-services-auth:$PLAY_SERVICES_VERSION"/> | ||
| <framework src="com.google.android.gms:play-services-auth-api-phone:$PLAY_SERVICES_VERSION"/> | ||
| <config-file target="res/xml/config.xml" parent="/*"> | ||
| <feature name="SMSRetriever"> | ||
| <param name="android-package" value="com.andreszs.smsretriever.SMSRetriever"/> | ||
| <param name="android-package" value="com.andreszs.smsretriever.SMSRetriever"/> | ||
| </feature> | ||
| </config-file> | ||
| <config-file target="AndroidManifest.xml" parent="application"> | ||
| <receiver android:exported="true" | ||
| android:name="com.andreszs.smsretriever.SMSBroadcastReceiver" | ||
| android:permission="com.google.android.gms.auth.api.phone.permission.SEND"> | ||
| <intent-filter> | ||
| <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" /> | ||
| </intent-filter> | ||
| </receiver> | ||
| </config-file> | ||
| <config-file target="AndroidManifest.xml" parent="/*"> | ||
@@ -43,4 +53,6 @@ <uses-feature android:name="android.hardware.telephony" android:required="false" /> | ||
| <source-file src="src/android/SMSRetriever.java" target-dir="src/com/andreszs/smsretriever" /> | ||
| <source-file src="src/android/SMSBroadcastReceiver.java" target-dir="src/com/andreszs/smsretriever" /> | ||
| <source-file src="src/android/AppSignatureHashHelper.java" target-dir="src/com/andreszs/smsretriever" /> | ||
| </platform> | ||
| </plugin> |
+74
-4
@@ -1,2 +0,2 @@ | ||
|   [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G33QACCVKYD7U) | ||
|        | ||
@@ -21,7 +21,46 @@ # cordova-plugin-sms-retriever | ||
| ## Ionic | ||
| ### Dev version: | ||
| ```bash | ||
| npm i awesome-cordova-plugins-sms-retriever-api | ||
| ``` | ||
| ### Prod version: https://github.com/danielsogl/awesome-cordova-plugins/pull/4528 | ||
| ```bash | ||
| npm i @awesome-cordova-plugins/sms-retriever-api | ||
| ``` | ||
| ## Ionic Demo | ||
| https://github.com/MaximBelov/cordova-plugin-sms-retriever-lab | ||
| # Methods | ||
| ## getPhoneNumber | ||
| Opens a dialog to select your mobile numbers saved in phone and [returns selected phone number](https://developers.google.com/identity/sms-retriever/request#1_obtain_the_users_phone_number). | ||
| ```javascript | ||
| var onSuccess = function (strSuccess) { | ||
| console.log(strSuccess); | ||
| }; | ||
| var onFail = function (strError) { | ||
| console.log(strError); | ||
| }; | ||
| cordova.plugins.SMSRetriever.getPhoneNumber(onSuccess, onFail); | ||
| ``` | ||
| ## startWatch | ||
| Start listening for a single incoming [verification SMS](https://developers.google.com/identity/sms-retriever/verify#1_construct_a_verification_message "verification SMS") for 5 minutes. | ||
| ```javascript | ||
| cordova.plugins.SMSRetriever.startWatch(successCallback, errorCallback); | ||
| ``` | ||
| :warning: Method moved from **window** to **cordova.plugins** object in version 2.0.0 | ||
@@ -52,2 +91,21 @@ | ||
| ## stopWatch | ||
| Stops listening for a single incoming verification SMS | ||
| ### Return values | ||
| - **SMS_RETRIEVER_DONE** | ||
| ### Example | ||
| ```javascript | ||
| var onSuccess = function (strSuccess) { | ||
| console.log(strSuccess); | ||
| }; | ||
| var onFail = function (strError) { | ||
| console.log(strError); | ||
| }; | ||
| cordova.plugins.SMSRetriever.stopWatch(onSuccess, onFail); | ||
| ``` | ||
| ## getHashString | ||
@@ -57,4 +115,10 @@ | ||
| ```javascript | ||
| cordova.plugins.SMSRetriever.getHashString(successCallback, errorCallback); | ||
| ``` | ||
| :warning: Method moved from **window** to **cordova.plugins** object in version 2.0.0 | ||
| ### Remarks | ||
@@ -119,3 +183,3 @@ | ||
| - Starting from **plugin 2.0.0**, the <#> prefix is no longer required by the plugin. | ||
| - Starting from an unknown **Play Services** version, the <#> is no longer required. | ||
| - Starting from an unknown **Play Services** version, the <#> is no longer required in the received SMS. | ||
@@ -130,5 +194,6 @@ Otherwise, the contents of the verification message can be whatever you choose. It is helpful to create a message from which you can easily extract the one-time code later on. For example, a valid verification message might look like the following: | ||
| You can download the [SMS Retriever plugin demo app](https://www.andreszsogon.com/cordova-sms-retriever-plugin-demo-app/) from the Play Store; its source code is provided in the **demo** folder. | ||
| - [Compiled APK and reference](https://www.andreszsogon.com/cordova-sms-retriever-plugin-demo-app/) including testing procedure instructions | ||
| - [Source code for www folder](https://github.com/andreszs/cordova-plugin-demos) | ||
| [](https://www.andreszsogon.com/cordova-sms-retriever-plugin-demo-app/) [](https://www.andreszsogon.com/cordova-sms-retriever-plugin-demo-app/) | ||
| <img src="https://github.com/andreszs/cordova-plugin-demos/blob/main/com.andreszs.smsretriever.demo/screenshots/sms_retriever_demo_2.png?raw=true" width="240" /> <img src="https://github.com/andreszs/cordova-plugin-demos/blob/main/com.andreszs.smsretriever.demo/screenshots/sms_retriever_demo_3.png?raw=true" width="240" /> <img src="https://github.com/andreszs/cordova-plugin-demos/blob/main/com.andreszs.smsretriever.demo/screenshots/sms_retriever_demo_4.png?raw=true" width="240" /> | ||
@@ -163,2 +228,7 @@ # FAQ | ||
| ### 3.0.0 | ||
| - Added method stopWatch | ||
| - Added method getPhoneNumber | ||
| ### 2.0.1 | ||
@@ -165,0 +235,0 @@ |
+221
-210
| package com.andreszs.smsretriever; | ||
| import android.Manifest; | ||
| import android.app.Activity; | ||
| import android.content.BroadcastReceiver; | ||
| import android.app.PendingIntent; | ||
| import android.content.Context; | ||
| import android.content.Intent; | ||
| import android.content.IntentFilter; | ||
| import android.content.pm.PackageManager; | ||
| import android.content.IntentSender; | ||
| import android.os.Bundle; | ||
| import android.util.Log; | ||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.Nullable; | ||
| import androidx.fragment.app.FragmentActivity; | ||
| import org.apache.cordova.CallbackContext; | ||
@@ -23,6 +26,10 @@ import org.apache.cordova.CordovaInterface; | ||
| import com.google.android.gms.auth.api.Auth; | ||
| import com.google.android.gms.auth.api.credentials.Credential; | ||
| import com.google.android.gms.auth.api.credentials.CredentialPickerConfig; | ||
| import com.google.android.gms.auth.api.credentials.HintRequest; | ||
| import com.google.android.gms.auth.api.phone.SmsRetriever; | ||
| import com.google.android.gms.auth.api.phone.SmsRetrieverClient; | ||
| import com.google.android.gms.common.api.CommonStatusCodes; | ||
| import com.google.android.gms.common.api.Status; | ||
| import com.google.android.gms.common.ConnectionResult; | ||
| import com.google.android.gms.common.api.GoogleApiClient; | ||
| import com.google.android.gms.tasks.OnFailureListener; | ||
@@ -32,236 +39,240 @@ import com.google.android.gms.tasks.OnSuccessListener; | ||
| /* AppSignatureHelper */ | ||
| import android.content.ContextWrapper; | ||
| import android.content.pm.Signature; | ||
| import android.util.Base64; | ||
| import android.util.Log; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.security.MessageDigest; | ||
| import java.security.NoSuchAlgorithmException; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| public class SMSRetriever extends CordovaPlugin { | ||
| public class SMSRetriever extends CordovaPlugin implements SMSBroadcastReceiver.OTPReceiveListener { | ||
| private static String LOG_TAG; | ||
| private static boolean STARTED = false; | ||
| private CallbackContext callbackContext; | ||
| private SmsRetrieverClient smsRetrieverClient; | ||
| private static String LOG_TAG; | ||
| private static final int RESOLVE_HINT = 234433; | ||
| private static GoogleApiClient apiClient; | ||
| private static final String ACTION_START_WATCH = "startWatch"; | ||
| private static final String ACTION_GET_SIGNATURE = "getHashString"; | ||
| private Context applicationContext; | ||
| private CallbackContext startWatchCallbackContext; | ||
| private CallbackContext getPhoneNumberCallbackContext; | ||
| private SMSBroadcastReceiver smsBroadcastReceiver; | ||
| /* AppSignatureHelper */ | ||
| private static final String HASH_TYPE = "SHA-256"; | ||
| public static final int NUM_HASHED_BYTES = 9; | ||
| public static final int NUM_BASE64_CHAR = 11; | ||
| private static final String ACTION_START_WATCH = "startWatch"; | ||
| private static final String ACTION_GET_SIGNATURE = "getHashString"; | ||
| private static final String ACTION_STOP_WATCH = "stopWatch"; | ||
| private static final String ACTION_GET_PHONE_NUMBER = "getPhoneNumber"; | ||
| public SMSRetriever() { | ||
| this.LOG_TAG = SMSRetriever.class.getSimpleName(); | ||
| Log.i(LOG_TAG, "Constructed"); | ||
| } | ||
| public SMSRetriever() { | ||
| LOG_TAG = SMSRetriever.class.getSimpleName(); | ||
| Log.i(LOG_TAG, "Constructed"); | ||
| } | ||
| @Override | ||
| public void initialize(CordovaInterface cordova, CordovaWebView webView) { | ||
| super.initialize(cordova, webView); | ||
| @Override | ||
| public void initialize(CordovaInterface cordova, CordovaWebView webView) { | ||
| super.initialize(cordova, webView); | ||
| applicationContext = cordova.getActivity().getApplicationContext(); | ||
| } | ||
| // Get an instance of SmsRetrieverClient, used to start listening for a matching SMS message. | ||
| smsRetrieverClient = SmsRetriever.getClient(cordova.getActivity().getApplicationContext()); | ||
| } | ||
| public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { | ||
| public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { | ||
| PluginResult result = null; | ||
| this.callbackContext = callbackContext; | ||
| Log.i(LOG_TAG, String.format("Executing the %s action started", action)); | ||
| Log.i(LOG_TAG, String.format("Executing the %s action started", action)); | ||
| if (action.equals(ACTION_START_WATCH)) { | ||
| this.startWatch(callbackContext); | ||
| } else if (action.equals(ACTION_GET_SIGNATURE)) { | ||
| this.getHashString(callbackContext); | ||
| } else { | ||
| Log.w(LOG_TAG, String.format("Invalid action passed: %s", action)); | ||
| result = new PluginResult(PluginResult.Status.INVALID_ACTION); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| return true; | ||
| } | ||
| switch (action) { | ||
| case ACTION_START_WATCH: | ||
| this.startWatch(callbackContext); | ||
| break; | ||
| case ACTION_STOP_WATCH: | ||
| this.stopWatch(callbackContext); | ||
| break; | ||
| case ACTION_GET_SIGNATURE: | ||
| this.getHashString(callbackContext); | ||
| break; | ||
| case ACTION_GET_PHONE_NUMBER: | ||
| this.getPhoneNumber(callbackContext); | ||
| break; | ||
| default: | ||
| Log.w(LOG_TAG, String.format("Invalid action passed: %s", action)); | ||
| PluginResult result = new PluginResult(PluginResult.Status.INVALID_ACTION); | ||
| callbackContext.sendPluginResult(result); | ||
| break; | ||
| } | ||
| return true; | ||
| } | ||
| public void onDestroy() { | ||
| if (SmsBrReceiver != null) { | ||
| try { | ||
| cordova.getActivity().getApplicationContext().unregisterReceiver(SmsBrReceiver); | ||
| SmsBrReceiver = null; | ||
| Log.i(LOG_TAG, "SMS Retriever unregistered successfully"); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| } | ||
| } | ||
| public void onDestroy() { | ||
| this.unregisterListeners(); | ||
| } | ||
| private void startWatch(final CallbackContext callbackContext) { | ||
| Log.i(LOG_TAG, ACTION_START_WATCH); | ||
| public void onSmsReceived(String smsMessage) { | ||
| Log.w(LOG_TAG, "SMS_RECEIVED"); | ||
| Log.w(LOG_TAG, smsMessage); | ||
| try { | ||
| JSONObject item = new JSONObject(); | ||
| item.put("sms", smsMessage); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, item); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| } catch (JSONException e) { | ||
| Log.e(LOG_TAG, e.getMessage(), e); | ||
| startWatchCallbackContext.error(e.getMessage()); | ||
| } | ||
| this.unregisterListeners(); | ||
| } | ||
| // Starts SmsRetriever, which waits for ONE matching SMS message until timeout | ||
| // (5 minutes). The matching SMS message will be sent via a Broadcast Intent with | ||
| // action SmsRetriever#SMS_RETRIEVED_ACTION. | ||
| try { | ||
| if(this.STARTED){ | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, "SMS_RETRIEVER_ALREADY_STARTED"); | ||
| result.setKeepCallback(true); | ||
| callbackContext.sendPluginResult(result); | ||
| }else{ | ||
| Task<Void> task = smsRetrieverClient.startSmsRetriever(); | ||
| public void onSmsReceiveTimeOut() { | ||
| Log.w(LOG_TAG, "TIMEOUT"); | ||
| PluginResult resultTimeout = new PluginResult(PluginResult.Status.ERROR, "TIMEOUT"); | ||
| startWatchCallbackContext.sendPluginResult(resultTimeout); | ||
| this.unregisterListeners(); | ||
| } | ||
| // Listen for success/failure of the start Task. | ||
| task.addOnSuccessListener(new OnSuccessListener<Void>() { | ||
| @Override | ||
| public void onSuccess(Void aVoid) { | ||
| // Successfully started retriever, expect broadcast intent | ||
| Log.i(LOG_TAG, "smsRetrieverClient started successfully"); | ||
| STARTED = true; | ||
| public void onSmsReceivedError(String error) { | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, error); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| this.unregisterListeners(); | ||
| } | ||
| // Use a BroadcastReceiver to receive the verification message. | ||
| IntentFilter intentFilter = new IntentFilter(); | ||
| intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION); | ||
| private void startWatch(final CallbackContext callbackContext) { | ||
| if (startWatchCallbackContext != null) { | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, "SMS_RETRIEVER_ALREADY_STARTED"); | ||
| callbackContext.sendPluginResult(result); | ||
| return; | ||
| } | ||
| // Starts SmsRetriever, which waits for ONE matching SMS message until timeout | ||
| // (5 minutes). The matching SMS message will be sent via a Broadcast Intent with | ||
| // action SmsRetriever#SMS_RETRIEVED_ACTION. | ||
| startWatchCallbackContext = callbackContext; | ||
| try { | ||
| smsBroadcastReceiver = new SMSBroadcastReceiver(); | ||
| smsBroadcastReceiver.setOTPListener(this); | ||
| try { | ||
| cordova.getActivity().getApplicationContext().registerReceiver(SmsBrReceiver, intentFilter); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, "SMS_RETRIEVER_STARTED"); | ||
| result.setKeepCallback(true); | ||
| callbackContext.sendPluginResult(result); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| }); | ||
| task.addOnFailureListener(new OnFailureListener() { | ||
| @Override | ||
| public void onFailure(Exception e) { | ||
| // Failed to start retriever, inspect Exception for more details | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| // Get an instance of SmsRetrieverClient, used to start listening for a matching SMS message. | ||
| SmsRetrieverClient smsRetrieverClient = SmsRetriever.getClient(applicationContext); | ||
| Task<Void> task = smsRetrieverClient.startSmsRetriever(); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| }); | ||
| } | ||
| // Listen for success/failure of the start Task. | ||
| task.addOnSuccessListener(new OnSuccessListener<Void>() { | ||
| @Override | ||
| public void onSuccess(Void aVoid) { | ||
| // Successfully started retriever, expect broadcast intent | ||
| Log.i(LOG_TAG, "smsRetrieverClient started successfully"); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| // Use a BroadcastReceiver to receive the verification message. | ||
| IntentFilter intentFilter = new IntentFilter(); | ||
| intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION); | ||
| /** | ||
| * Google Play services uses the hash string to determine which verification messages to send to your app. The hash string is made of your app's package name and your app's public key certificate. https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string | ||
| */ | ||
| private void getHashString(final CallbackContext callbackContext) { | ||
| try { | ||
| applicationContext.registerReceiver(smsBroadcastReceiver, intentFilter); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, "SMS_RETRIEVER_STARTED"); | ||
| result.setKeepCallback(true); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| }); | ||
| task.addOnFailureListener(new OnFailureListener() { | ||
| @Override | ||
| public void onFailure(Exception e) { | ||
| // Failed to start retriever, inspect Exception for more details | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| } | ||
| }); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, e.getMessage()); | ||
| startWatchCallbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| ArrayList<String> appCodes = this.getAppSignatures(); | ||
| private void stopWatch(final CallbackContext callbackContext) { | ||
| callbackContext.success(); | ||
| if (startWatchCallbackContext != null) { | ||
| startWatchCallbackContext.success("SMS_RETRIEVER_DONE"); | ||
| } | ||
| this.unregisterListeners(); | ||
| } | ||
| if (appCodes.size() == 0 || appCodes.get(0) == null) { | ||
| String err = "Unable to find package to obtain hash"; | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, err); | ||
| callbackContext.sendPluginResult(result); | ||
| } else { | ||
| String hash = appCodes.get(0); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, hash); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| private void unregisterListeners() { | ||
| if (smsBroadcastReceiver != null) { | ||
| try { | ||
| applicationContext.unregisterReceiver(smsBroadcastReceiver); | ||
| smsBroadcastReceiver = null; | ||
| Log.i(LOG_TAG, "SMS Retriever unregistered successfully"); | ||
| } catch (Exception e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| } | ||
| /** | ||
| * BroadcastReceiver to wait for SMS messages. This can be registered either in the AndroidManifest or at runtime. Should filter Intents on SmsRetriever.SMS_RETRIEVED_ACTION. | ||
| */ | ||
| private BroadcastReceiver SmsBrReceiver = new BroadcastReceiver() { | ||
| @Override | ||
| public void onReceive(Context context, Intent intent) { | ||
| if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) { | ||
| Bundle extras = intent.getExtras(); | ||
| Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS); | ||
| JSONObject item = new JSONObject(); | ||
| if (startWatchCallbackContext != null) { | ||
| startWatchCallbackContext = null; | ||
| } | ||
| } | ||
| switch (status.getStatusCode()) { | ||
| case CommonStatusCodes.SUCCESS: | ||
| // Get SMS message contents | ||
| String smsMessage = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE); | ||
| Log.i(LOG_TAG, smsMessage); | ||
| STARTED = false; | ||
| private void getPhoneNumber(final CallbackContext callbackContext) { | ||
| this.getPhoneNumberCallbackContext = callbackContext; | ||
| try { | ||
| FragmentActivity activity = cordova.getActivity(); | ||
| if (apiClient == null) { | ||
| apiClient = new GoogleApiClient.Builder(activity).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { | ||
| @Override | ||
| public void onConnected(@Nullable Bundle bundle) { | ||
| Log.d(LOG_TAG, "onConnected: "); | ||
| } | ||
| try { | ||
| item.put("sms", smsMessage); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, item); | ||
| callbackContext.sendPluginResult(result); | ||
| } catch (JSONException e) { | ||
| Log.e(LOG_TAG, e.getMessage(), e); | ||
| callbackContext.error(e.getMessage()); | ||
| } | ||
| @Override | ||
| public void onConnectionSuspended(int i) { | ||
| Log.d(LOG_TAG, "onConnectionSuspended: "); | ||
| } | ||
| }).enableAutoManage(activity, new GoogleApiClient.OnConnectionFailedListener() { | ||
| @Override | ||
| public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { | ||
| } | ||
| }).addApi(Auth.CREDENTIALS_API).build(); | ||
| } | ||
| break; | ||
| HintRequest hintRequest = new HintRequest.Builder().setHintPickerConfig(new CredentialPickerConfig.Builder().setShowCancelButton(true).build()).setPhoneNumberIdentifierSupported(true).build(); | ||
| case CommonStatusCodes.TIMEOUT: | ||
| // Waiting for SMS timed out (5 minutes) | ||
| Log.w(LOG_TAG, "TIMEOUT"); | ||
| STARTED = false; | ||
| PluginResult resultTimeout = new PluginResult(PluginResult.Status.ERROR, "TIMEOUT"); | ||
| callbackContext.sendPluginResult(resultTimeout); | ||
| cordova.setActivityResultCallback(this); | ||
| PendingIntent hintPickerIntent = Auth.CredentialsApi.getHintPickerIntent(apiClient, hintRequest); | ||
| activity.startIntentSenderForResult(hintPickerIntent.getIntentSender(), RESOLVE_HINT, null, 0, 0, 0); | ||
| } catch (IntentSender.SendIntentException e) { | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
| break; | ||
| } | ||
| @Override | ||
| public void onActivityResult(int requestCode, int resultCode, Intent intent) { | ||
| super.onActivityResult(requestCode, resultCode, intent); | ||
| String phoneNumber = null; | ||
| try { | ||
| if (requestCode == RESOLVE_HINT) { | ||
| if (resultCode == Activity.RESULT_OK) { | ||
| Credential credential = intent.getParcelableExtra(Credential.EXTRA_KEY); | ||
| phoneNumber = credential.getId(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| if (phoneNumber != null) { | ||
| getPhoneNumberCallbackContext.success(phoneNumber); | ||
| } else { | ||
| getPhoneNumberCallbackContext.error("Phone number not selected."); | ||
| } | ||
| } catch (Exception ex) { | ||
| ex.printStackTrace(); | ||
| getPhoneNumberCallbackContext.error(ex.getMessage()); | ||
| } | ||
| } | ||
| /** | ||
| * Get all the app signatures for the current package https://github.com/googlesamples/android-credentials/blob/master/sms-verification/android/app/src/main/java/com/google/samples/smartlock/sms_verify/AppSignatureHelper.java | ||
| * | ||
| * @return | ||
| */ | ||
| private ArrayList<String> getAppSignatures() { | ||
| ArrayList<String> appCodes = new ArrayList<String>(); | ||
| try { | ||
| // Get all package signatures for the current package | ||
| String packageName = cordova.getActivity().getApplicationContext().getPackageName(); | ||
| PackageManager packageManager = cordova.getActivity().getApplicationContext().getPackageManager(); | ||
| Signature[] signatures = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures; | ||
| // For each signature create a compatible hash | ||
| for (Signature signature : signatures) { | ||
| String hash = hash(packageName, signature.toCharsString()); | ||
| if (hash != null) { | ||
| appCodes.add(String.format("%s", hash)); | ||
| } | ||
| } | ||
| } catch (PackageManager.NameNotFoundException e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| return appCodes; | ||
| } | ||
| private static String hash(String packageName, String signature) { | ||
| String appInfo = packageName + " " + signature; | ||
| try { | ||
| MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE); | ||
| messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8)); | ||
| byte[] hashSignature = messageDigest.digest(); | ||
| // truncated into NUM_HASHED_BYTES | ||
| hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES); | ||
| // encode into Base64 | ||
| String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP); | ||
| base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR); | ||
| return base64Hash; | ||
| } catch (NoSuchAlgorithmException e) { | ||
| Log.e(LOG_TAG, e.getMessage()); | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * Google Play services uses the hash string to determine which verification messages to send to your app. The hash string is made of your app's package name and your app's public key certificate. https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string | ||
| */ | ||
| private void getHashString(final CallbackContext callbackContext) { | ||
| ArrayList<String> appCodes = new AppSignatureHashHelper(applicationContext).getAppSignatures(); | ||
| if (appCodes.size() == 0 || appCodes.get(0) == null) { | ||
| String err = "Unable to find package to obtain hash"; | ||
| PluginResult result = new PluginResult(PluginResult.Status.ERROR, err); | ||
| callbackContext.sendPluginResult(result); | ||
| } else { | ||
| String hash = appCodes.get(0); | ||
| PluginResult result = new PluginResult(PluginResult.Status.OK, hash); | ||
| callbackContext.sendPluginResult(result); | ||
| } | ||
| } | ||
| } |
@@ -17,7 +17,13 @@ var exec = require('cordova/exec'); | ||
| }, | ||
| stopWatch: function (successCallback, failureCallback) { | ||
| exec(successCallback, failureCallback, 'SMSRetriever', 'stopWatch', []); | ||
| }, | ||
| getHashString: function (successCallback, failureCallback) { | ||
| exec(successCallback, failureCallback, 'SMSRetriever', 'getHashString', []); | ||
| } | ||
| }, | ||
| getPhoneNumber: function (successCallback, failureCallback) { | ||
| exec(successCallback, failureCallback, 'SMSRetriever', 'getPhoneNumber', []); | ||
| }, | ||
| }; | ||
| module.exports = smsRetriever; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
33601
48.16%10
25%391
59.59%238
41.67%