Skip to content

Instantly share code, notes, and snippets.

@cutiko
Last active September 14, 2021 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cutiko/358185f4173e139db2f85a85364050f2 to your computer and use it in GitHub Desktop.
Save cutiko/358185f4173e139db2f85a85364050f2 to your computer and use it in GitHub Desktop.
Sms login
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;
//ORIGINAL HAVING IT HERE JUST IN CASE
//https://github.com/googlearchive/android-credentials/blob/master/sms-verification/android/app/src/main/java/com/google/samples/smartlock/sms_verify/AppSignatureHelper.java
/**
* This is a helper class to generate your message hash to be included in your SMS message.
*
* Without the correct hash, your app won't recieve the message callback. This only needs to be
* generated once per app and stored. Then you can remove this helper class from your code.
*/
public class 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;
/**
* This is a helper class to generate your message hash to be included in your SMS message.
*
* Without the correct hash, your app won't recieve the message callback. This only needs to be
* generated once per app and stored. Then you can remove this helper class from your code.
*/
public class AppSignatureHelper extends ContextWrapper {
public static final String TAG = AppSignatureHelper.class.getSimpleName();
private static final String HASH_TYPE = "SHA-256";
public static final int NUM_HASHED_BYTES = 9;
public static final int NUM_BASE64_CHAR = 11;
public AppSignatureHelper(Context context) {
super(context);
}
/**
* Get all the app signatures for the current package
* @return
*/
public ArrayList<String> getAppSignatures() {
ArrayList<String> appCodes = new ArrayList<>();
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(TAG, "Unable to find package to obtain hash.", e);
}
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);
Log.d(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash));
return base64Hash;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "hash:NoSuchAlgorithm", e);
}
return null;
}
}
//carefull with this crash
//java.lang.RuntimeException: Error receiving broadcast Intent { act=com.google.android.gms.auth.api.phone.SMS_RETRIEVED flg=0x200010 pkg=com.your.package.coolapp (has extras) } in com.your.package.coolapp.SomeFragment$1@e9d5441
private fun foo() = lifecycleScope.launch {
Log.d("CUTIKO_TAG", "starting the process")
val client = SmsRetriever.getClient(requireContext())
try {
client.startSmsUserConsent(null).await() // no phone number needed if specified only listen for that
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent == null) {
Log.d("CUTIKO_TAG", "intent was null")
return
}
if (SmsRetriever.SMS_RETRIEVED_ACTION != intent.action) {
Log.d("CUTIKO_TAG", "received something but not sms action")
return
}
val extras = intent.extras
if (extras == null) {
Log.d("CUTIKO_TAG", "extras was null")
return
}
val status = extras.get(SmsRetriever.EXTRA_STATUS) as? Status
if (status == null) {
Log.d("CUTIKO_TAG", "status is null")
return
}
when (status.statusCode) {
CommonStatusCodes.SUCCESS -> {
val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
//try/catch? deprecated?
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
}
CommonStatusCodes.TIMEOUT -> {
Log.d("CUTIKO_TAG", "time out")
}
else -> Log.d("CUTIKO_TAG", "the status was different than success or error ${status.statusCode}")
}
}
}
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
requireContext().registerReceiver(broadcastReceiver, intentFilter, SmsRetriever.SEND_PERMISSION, null)
Log.d("CUTIKO_TAG", "registered and ready to go")
} catch (exception: Exception) {
Log.d("CUTIKO_TAG", "exception", exception)
}
}
//TODO deprecated?
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (SMS_CONSENT_REQUEST == requestCode) {
if (resultCode == Activity.RESULT_OK && data != null) {
val message = data?.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
Log.d("CUTIKO_TAG", "message: $message")
} else Log.d("CUTIKO_TAG", "denied by the user")
}
}
//AppSignature helper -> https://github.com/googlearchive/android-credentials/blob/master/sms-verification/android/app/src/main/java/com/google/samples/smartlock/sms_verify/AppSignatureHelper.java
fun foo() = lifecycleScope.launch {
val signatureHelper = AppSignatureHelper(requireContext())
Log.d("CUTIKO_TAG", "#################### SIGNATURE ####################")
Log.d("CUTIKO_TAG", "${signatureHelper.appSignatures}")
Log.d("CUTIKO_TAG", "#################### SIGNATURE ####################")
Log.d("CUTIKO_TAG", "starting the process")
val client = SmsRetriever.getClient(requireContext())
try {
client.startSmsRetriever().await()
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent == null) {
Log.d("CUTIKO_TAG", "intent was null")
return
}
if (SmsRetriever.SMS_RETRIEVED_ACTION != intent?.action) {
Log.d("CUTIKO_TAG", "received something but not sms action")
return
}
val extras = intent.extras
if (extras == null) {
Log.d("CUTIKO_TAG", "extras was null")
return
}
val status = extras.get(SmsRetriever.EXTRA_STATUS) as? Status
if (status == null) {
Log.d("CUTIKO_TAG", "status is null")
return
}
when (status.statusCode) {
CommonStatusCodes.SUCCESS -> {
val message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE)
Log.d("CUTIKO_TAG", "$message")
}
CommonStatusCodes.TIMEOUT -> {
Log.d("CUTIKO_TAG", "time out")
}
else -> Log.d("CUTIKO_TAG", "the status was different than success or error ${status.statusCode}")
}
}
}
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
requireContext().registerReceiver(broadcastReceiver, intentFilter, SmsRetriever.SEND_PERMISSION, null)
Log.d("CUTIKO_TAG", "registered and ready to go")
} catch (exception: Exception) {
Log.d("CUTIKO_TAG", "exception", exception)
}
}
@cutiko
Copy link
Author

cutiko commented Aug 17, 2021

Required libraries

    implementation 'com.google.android.gms:play-services-auth:19.2.0'
    implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.1'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.5.1"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment