Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,44 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.json.JSONException;

@CapacitorPlugin(name = "Share")
public class SharePlugin extends Plugin {

private static final String NONCE_EXTRA_KEY = "_share_nonce";

private BroadcastReceiver broadcastReceiver;
private boolean stopped = false;
private boolean isPresenting = false;
private ComponentName chosenComponent;
private String expectedNonce;

@Override
public void load() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Validate nonce to prevent spoofing from other apps
// Reference: https://github.com/ionic-team/capacitor-plugins/pull/2592
String receivedNonce = intent.getStringExtra(NONCE_EXTRA_KEY);
if (receivedNonce == null || !receivedNonce.equals(expectedNonce)) {
// Reject broadcasts that don't have the correct nonce
return;
}

ComponentName component;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
chosenComponent = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName.class);
component = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName.class);
} else {
chosenComponent = getParcelableExtraLegacy(intent, Intent.EXTRA_CHOSEN_COMPONENT);
component = getParcelableExtraLegacy(intent, Intent.EXTRA_CHOSEN_COMPONENT);
}

// Only clear nonce if we successfully got the component data
if (component != null) {
chosenComponent = component;
expectedNonce = null;
}
}
};
Expand All @@ -64,6 +83,7 @@ private void activityResult(PluginCall call, ActivityResult result) {
call.resolve(callResult);
}
isPresenting = false;
expectedNonce = null;
}

@PluginMethod
Expand Down Expand Up @@ -117,6 +137,12 @@ public void share(PluginCall call) {
if (files != null && files.length() != 0) {
shareFiles(files, intent, call);
}

// Generate a random nonce to prevent spoofing via exported receiver
expectedNonce = UUID.randomUUID().toString();
Intent callbackIntent = new Intent(Intent.EXTRA_CHOSEN_COMPONENT);
callbackIntent.putExtra(NONCE_EXTRA_KEY, expectedNonce);

int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flags = flags | PendingIntent.FLAG_MUTABLE;
Expand All @@ -126,7 +152,7 @@ public void share(PluginCall call) {
}

// requestCode parameter is not used. Providing 0
PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, new Intent(Intent.EXTRA_CHOSEN_COMPONENT), flags);
PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, callbackIntent, flags);
Intent chooser = Intent.createChooser(intent, dialogTitle, pi.getIntentSender());
chosenComponent = null;
chooser.addCategory(Intent.CATEGORY_DEFAULT);
Expand Down Expand Up @@ -180,6 +206,7 @@ private void shareFiles(JSArray files, Intent intent, PluginCall call) {

@Override
protected void handleOnDestroy() {
expectedNonce = null;
if (broadcastReceiver != null) {
getActivity().unregisterReceiver(broadcastReceiver);
}
Expand Down
Loading