mirror of
https://github.com/standardnotes/app
synced 2026-01-16 19:04:58 -05:00
wip: key handles encoding
This commit is contained in:
@@ -4,8 +4,8 @@ import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.util.Log;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ActivityEventListener;
|
||||
@@ -13,6 +13,7 @@ import com.facebook.react.bridge.BaseActivityEventListener;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
@@ -22,6 +23,7 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import com.google.android.gms.fido.fido2.Fido2ApiClient;
|
||||
import com.google.android.gms.fido.fido2.api.common.AuthenticatorErrorResponse;
|
||||
import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialType;
|
||||
import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor;
|
||||
import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions;
|
||||
@@ -36,6 +38,11 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
private final ReactApplicationContext reactContext;
|
||||
private static final int SIGN_REQUEST_CODE = 111;
|
||||
|
||||
private static final String LOGS_TAG = "Fido2ApiModule";
|
||||
private static final String RP_ID = "app.standardnotes.com";
|
||||
|
||||
private Promise signInPromise;
|
||||
|
||||
private final ActivityEventListener activityEventListener = new BaseActivityEventListener() {
|
||||
@Override
|
||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
|
||||
@@ -43,12 +50,26 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
|
||||
if (requestCode == SIGN_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
byte[] response = intent.getByteArrayExtra(Fido.FIDO2_KEY_RESPONSE_EXTRA);
|
||||
String responseString = Base64.encodeToString(response, Base64.DEFAULT);
|
||||
Log.i("Fido2ApiModule", "FIDO response: " + responseString);
|
||||
if (intent.hasExtra(Fido.FIDO2_KEY_ERROR_EXTRA)) {
|
||||
AuthenticatorErrorResponse authenticatorErrorResponse =
|
||||
AuthenticatorErrorResponse.deserializeFromBytes(intent.getByteArrayExtra(Fido.FIDO2_KEY_ERROR_EXTRA));
|
||||
Log.e(LOGS_TAG, "FIDO2_KEY_ERROR_EXTRA Security Key: " + authenticatorErrorResponse.getErrorMessage());
|
||||
|
||||
signInPromise.reject("FIDO2_KEY_ERROR_EXTRA", authenticatorErrorResponse.getErrorMessage());
|
||||
|
||||
signInPromise = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(LOGS_TAG, "FIDO response OK");
|
||||
signInPromise.resolve("OK");
|
||||
} else {
|
||||
Log.e("Fido2ApiModule", "FIDO sign in failed");
|
||||
Log.e(LOGS_TAG, "FIDO sign in failed");
|
||||
signInPromise.reject("FIDO_SIGN_IN_FAILED", "FIDO sign in failed");
|
||||
}
|
||||
|
||||
signInPromise = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -68,31 +89,42 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void promptForU2FAuthentication(String authenticationOptionsJSONString) throws JSONException {
|
||||
Log.i("Fido2ApiModule", "Prompt for U2F sign in with options: " + authenticationOptionsJSONString);
|
||||
public void promptForU2FAuthentication(String authenticationOptionsJSONString, Promise promise) throws JSONException {
|
||||
Log.i(LOGS_TAG, "Prompt for U2F sign in with options: " + authenticationOptionsJSONString);
|
||||
|
||||
signInPromise = promise;
|
||||
|
||||
JSONObject authenticationOptions = new JSONObject(authenticationOptionsJSONString);
|
||||
|
||||
ArrayList<PublicKeyCredentialDescriptor> allowedKeys = new ArrayList<PublicKeyCredentialDescriptor>();
|
||||
|
||||
JSONArray keyHandles = authenticationOptions.getJSONArray("allowCredentials");
|
||||
for (int i = 0, size = keyHandles.length(); i < size; i++) {
|
||||
JSONObject keyHandle = keyHandles.getJSONObject(i);
|
||||
JSONArray allowedCredentials = authenticationOptions.getJSONArray("allowCredentials");
|
||||
for (int i = 0, size = allowedCredentials.length(); i < size; i++) {
|
||||
JSONObject allowedCredential = allowedCredentials.getJSONObject(i);
|
||||
Log.i(LOGS_TAG, "Adding credential id: " + allowedCredential.getString("id"));
|
||||
|
||||
allowedKeys.add(
|
||||
new PublicKeyCredentialDescriptor(
|
||||
PublicKeyCredentialType.PUBLIC_KEY.toString(),
|
||||
keyHandle.getString("id").getBytes(),
|
||||
this.convertBase64URLStringToBytes(allowedCredential.getString("id")),
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
String challenge = authenticationOptions.getString("challenge");
|
||||
Double timeout = authenticationOptions.getDouble("timeout");
|
||||
Log.i(LOGS_TAG, "Challenge: " + challenge);
|
||||
Log.i(LOGS_TAG, "Timeout: " + timeout);
|
||||
Log.i(LOGS_TAG, "RP ID: " + RP_ID);
|
||||
Log.i(LOGS_TAG, "Allowed keys size: " + allowedKeys.size());
|
||||
|
||||
PublicKeyCredentialRequestOptions.Builder optionsBuilder = new PublicKeyCredentialRequestOptions
|
||||
.Builder()
|
||||
.setRpId("app.standardnotes.com")
|
||||
.setRpId(RP_ID)
|
||||
.setAllowList(allowedKeys)
|
||||
.setChallenge(authenticationOptions.getString("challenge").getBytes())
|
||||
.setTimeoutSeconds(authenticationOptions.getDouble("timeout"));
|
||||
.setChallenge(this.convertBase64URLStringToBytes(challenge))
|
||||
.setTimeoutSeconds(timeout);
|
||||
|
||||
PublicKeyCredentialRequestOptions options = optionsBuilder.build();
|
||||
|
||||
@@ -105,7 +137,7 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
@Override
|
||||
public void onSuccess(PendingIntent fido2PendingIntent) {
|
||||
if (fido2PendingIntent == null) {
|
||||
Log.e("Fido2ApiModule", "No pending FIDO intent returned");
|
||||
Log.e(LOGS_TAG, "No pending FIDO intent returned");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +151,7 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
0
|
||||
);
|
||||
} catch (IntentSender.SendIntentException exception) {
|
||||
Log.e("Fido2ApiModule", "Error starting FIDO intent: " + exception.getMessage());
|
||||
Log.e(LOGS_TAG, "Error starting FIDO intent: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,9 +161,22 @@ public class Fido2ApiModule extends ReactContextBaseJavaModule {
|
||||
new OnFailureListener() {
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
Log.e("Fido2ApiModule", "Error getting FIDO intent: " + e.getMessage());
|
||||
Log.e(LOGS_TAG, "Error getting FIDO intent: " + e.getMessage());
|
||||
signInPromise.reject("unknown", e.getMessage());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private byte[] convertBase64URLStringToBytes(String base64URLString) {
|
||||
String base64String = base64URLString.replace('-', '+').replace('_', '/');
|
||||
int padding = (4 - (base64String.length() % 4)) % 4;
|
||||
for (int i = 0; i < padding; i++) {
|
||||
base64String += '=';
|
||||
}
|
||||
|
||||
byte[] decoded = Base64.decode(base64String, Base64.DEFAULT);
|
||||
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,4 +43,7 @@ newArchEnabled=false
|
||||
hermesEnabled=true
|
||||
|
||||
# Set AsyncStorage limit
|
||||
AsyncStorage_db_size_in_MB=50
|
||||
AsyncStorage_db_size_in_MB=50
|
||||
|
||||
# The URL of the server
|
||||
host=https://app.standardnotes.com
|
||||
|
||||
@@ -75,7 +75,13 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
async promptForU2FAuthentication(authenticationOptionsJSONString: string): Promise<void> {
|
||||
const { Fido2ApiModule } = NativeModules
|
||||
|
||||
await Fido2ApiModule.promptForU2FAuthentication(authenticationOptionsJSONString)
|
||||
try {
|
||||
const response = await Fido2ApiModule.promptForU2FAuthentication(authenticationOptionsJSONString)
|
||||
|
||||
this.consoleLog('Fido2ApiModule.promptForU2FAuthentication response', response)
|
||||
} catch (error) {
|
||||
this.consoleLog('Fido2ApiModule.promptForU2FAuthentication error', (error as Error).message)
|
||||
}
|
||||
}
|
||||
|
||||
purchaseSubscriptionIAP(plan: AppleIAPProductId): Promise<AppleIAPReceipt | undefined> {
|
||||
|
||||
Reference in New Issue
Block a user