Skip to content

Commit

Permalink
add new functionality "install CA certificate"
Browse files Browse the repository at this point in the history
  • Loading branch information
tfels committed Dec 17, 2023
1 parent e20ef7a commit b500a9d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Features
===

- Installing apps inside a work profile for isolation
- Installing CA certificates inside a work profile
- "Freeze" apps inside the work profile to prevent them from running or being woken up when you are not actively using them
- Installing two copies of the same app on the same device

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface IShelterService {
void loadIcon(in ApplicationInfoWrapper info, ILoadIconCallback callback);
void installApp(in ApplicationInfoWrapper app, IAppInstallCallback callback);
void installApk(in UriForwardProxy uri, IAppInstallCallback callback);
void installCaCert(in UriForwardProxy uri, IAppInstallCallback callback);
void uninstallApp(in ApplicationInfoWrapper app, IAppInstallCallback callback);
void freezeApp(in ApplicationInfoWrapper app);
void unfreezeApp(in ApplicationInfoWrapper app);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;

import androidx.annotation.Nullable;
Expand All @@ -25,13 +26,16 @@
import net.typeblog.shelter.util.UriForwardProxy;
import net.typeblog.shelter.util.Utility;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

public class ShelterService extends Service {
public static final int RESULT_CANNOT_INSTALL_SYSTEM_APP = 100001;
public static final int RESULT_CANNOT_INSTALL_CA_CERT = 100002;

private static final int NOTIFICATION_ID = 0x49a11;
private DevicePolicyManager mPolicyManager = null;
Expand Down Expand Up @@ -186,6 +190,31 @@ public void installApk(UriForwardProxy uriForwarder, IAppInstallCallback callbac
mStartActivityProxy.startActivity(intent);
}

@Override
public void installCaCert(UriForwardProxy uriForwarder, IAppInstallCallback callback) throws RemoteException {

// read certificate file
byte[] certData = {};
try {
ParcelFileDescriptor fd = uriForwarder.open("r");
FileInputStream fileInputStream = new FileInputStream(fd.getFileDescriptor());
certData = new byte[fileInputStream.available()];
fileInputStream.read(certData);
fd.close();
} catch (IOException e) {
callback.callback(RESULT_CANNOT_INSTALL_CA_CERT);
return;
}

// install certificate
if (mIsProfileOwner) {
if (!mPolicyManager.installCaCert(mAdminComponent, certData))
callback.callback(RESULT_CANNOT_INSTALL_CA_CERT);
else
callback.callback(Activity.RESULT_OK);
}
}

@Override
public void uninstallApp(ApplicationInfoWrapper app, IAppInstallCallback callback) throws RemoteException {
if (!app.isSystem()) {
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/net/typeblog/shelter/ui/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public class MainActivity extends AppCompatActivity {
new ActivityResultContracts.OpenDocument(),
new String[]{"application/vnd.android.package-archive"}),
this::onApkSelected);
private final ActivityResultLauncher<Void> mSelectCaCert =
registerForActivityResult(
new Utility.ActivityResultContractInputWrapper<>(
new ActivityResultContracts.OpenDocument(),
new String[]{"application/x-pem-file"}),
this::onCaCertSelected);
// Logic of the following intents are quite complicated; use the generic contract for more control
private final ActivityResultLauncher<Intent> mTryStartWorkService =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this::tryStartWorkServiceCb);
Expand Down Expand Up @@ -412,6 +418,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
} else if (itemId == R.id.main_menu_install_app_to_profile) {
mSelectApk.launch(null);
return true;
} else if (itemId == R.id.main_menu_install_ca_cert) {
mSelectCaCert.launch(null);
return true;
} else if (itemId == R.id.main_menu_show_all) {
Runnable update = () -> {
mShowAll = !item.isChecked();
Expand Down Expand Up @@ -461,4 +470,28 @@ public void callback(int result) {
// Well, I don't know what to do then
}
}

private void onCaCertSelected(Uri uri) {
if (uri == null) return;
UriForwardProxy proxy = new UriForwardProxy(getApplicationContext(), uri);

try {
mServiceWork.installCaCert(proxy, new IAppInstallCallback.Stub() {
@Override
public void callback(int result) {
runOnUiThread(() -> {
// The other side will have closed the Fd for us
if (result == RESULT_OK)
Toast.makeText(MainActivity.this,
R.string.install_ca_cert_to_profile_success, Toast.LENGTH_LONG).show();
else
Toast.makeText(MainActivity.this,
R.string.install_ca_cert_to_profile_failure, Toast.LENGTH_LONG).show();
});
}
});
} catch (RemoteException e) {
// Well, I don't know what to do then
}
}
}
4 changes: 4 additions & 0 deletions app/src/main/res/menu/main_activity_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
android:id="@+id/main_menu_install_app_to_profile"
android:title="@string/install_app_to_profile" />

<item
android:id="@+id/main_menu_install_ca_cert"
android:title="@string/install_ca_cert_to_profile" />

<item
android:id="@+id/main_menu_documents_ui"
android:title="@string/documents_ui" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
<string name="freeze_all_shortcut">Freeze</string>
<string name="install_app_to_profile">Install APK into Shelter</string>
<string name="install_app_to_profile_success">Application installation finished in work profile.</string>
<string name="install_ca_cert_to_profile">Install CA certificate into Shelter</string>
<string name="install_ca_cert_to_profile_success">CA certificate successfully installed in work profile.</string>
<string name="install_ca_cert_to_profile_failure">Failed to install CA certificate in work profile.</string>
<string name="show_all">Show All Apps</string>
<string name="show_all_warning">Manipulating apps that are hidden from the list could cause crashes and all sorts of unexpected behavior. However, this feature can be useful when faulty vendor-customized ROMs does not enable all necessary system apps in work profile by default. If you continue, you are on your own.</string>
<string name="documents_ui">Open Documents UI</string>
Expand Down

0 comments on commit b500a9d

Please sign in to comment.