AXP Magisk resurrection track: Speckit 009 port AXP/LOS22 to LOS23.
Ship Magisk like GOLDEN; KernelSU optional recycle only; parallel to sunfish-a16-rom standby.
This commit is contained in:
commit
12d2179c20
150 files changed
+26263
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# 005 sigspoof patches
|
||||
|
||||
Idempotent apply script for `rom-dev01` LOS 23.2 tree.
|
||||
|
||||
```bash
|
||||
python3 vendor/sunfish-a16/patches/005-sigspoof/apply_005_sigspoof.py
|
||||
```
|
||||
|
||||
Requires `/srv/rom/artifacts/005-spoofing/phonesky-cert.hex` (DER hex of
|
||||
project Phonesky signer).
|
||||
|
||||
See `docs/005-spoofing-runbook.md`.
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,634 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Apply sunfish-a16 005 signature spoofing extensions on LOS 23.2 tree.
|
||||
|
||||
Builds on LuK1337 microG allow-list spoofing already in ComputerEngine:
|
||||
- Accept project-signed Phonesky (not only MICROG_REAL)
|
||||
- Gate on Settings.Secure.allow_signature_fake (default off)
|
||||
- Require FAKE_PACKAGE_SIGNATURE grant (EXTENDROM-style; Self-Check)
|
||||
- Add permission + Developer Options toggle (EXTENDROM A15 port)
|
||||
|
||||
Attribution: EXTENDROM (steadfasterX), LineageOS microG spoof (LuK1337).
|
||||
Run on rom-dev01: python3 apply_005_sigspoof.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
TREE = Path("/srv/rom/src/lineage")
|
||||
PHONESKY_HEX = Path("/srv/rom/artifacts/005-spoofing/phonesky-cert.hex").read_text().strip()
|
||||
MARKER = "SUNFISH_A16_005_SIGSPOOF"
|
||||
|
||||
|
||||
def backup(path: Path) -> None:
|
||||
# Never leave *.bak inside source trees (aapt2 compiles everything under res/).
|
||||
bak_root = Path("/srv/rom/artifacts/005-spoofing/bak-snapshots")
|
||||
bak_root.mkdir(parents=True, exist_ok=True)
|
||||
rel = path
|
||||
try:
|
||||
rel = path.relative_to(TREE)
|
||||
except ValueError:
|
||||
pass
|
||||
bak = bak_root / str(rel).replace("/", "_")
|
||||
if not bak.exists():
|
||||
shutil.copy2(path, bak)
|
||||
|
||||
|
||||
def patch_computer_engine() -> None:
|
||||
path = TREE / "frameworks/base/services/core/java/com/android/server/pm/ComputerEngine.java"
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("ComputerEngine: already patched")
|
||||
return
|
||||
backup(path)
|
||||
|
||||
real_pat = re.compile(
|
||||
r'(private static final Signature MICROG_REAL_SIGNATURE = new Signature\("[0-9a-f]+"\);)'
|
||||
)
|
||||
m = real_pat.search(text)
|
||||
if not m:
|
||||
raise SystemExit("MICROG_REAL_SIGNATURE not found")
|
||||
insert = (
|
||||
m.group(1)
|
||||
+ "\n\n"
|
||||
+ " // %s: project JKS for patched Phonesky (sha256 "
|
||||
"313186cb7df2d40133721207b72973e852f61c8767c321e5c75039011b83bd56)\n"
|
||||
% MARKER
|
||||
+ ' private static final Signature SUNFISH_PHONESKY_SIGNATURE = new Signature("%s");'
|
||||
% PHONESKY_HEX
|
||||
)
|
||||
text = real_pat.sub(insert, text, count=1)
|
||||
|
||||
old_is = """ public static boolean isMicrogSigned(AndroidPackage p) {
|
||||
if (!isDebuggable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allowlist the following apps:
|
||||
// * com.android.vending - microG Companion
|
||||
// * com.google.android.gms - microG Services
|
||||
if (!p.getPackageName().equals("com.android.vending") &&
|
||||
!p.getPackageName().equals("com.google.android.gms")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Signature.areExactMatch(
|
||||
p.getSigningDetails(), new Signature[]{MICROG_REAL_SIGNATURE});
|
||||
}"""
|
||||
|
||||
new_is = """ public static boolean isMicrogSigned(AndroidPackage p) {
|
||||
if (!isDebuggable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allowlist the following apps:
|
||||
// * com.android.vending - microG Companion / patched Phonesky
|
||||
// * com.google.android.gms - microG Services
|
||||
if (!p.getPackageName().equals("com.android.vending") &&
|
||||
!p.getPackageName().equals("com.google.android.gms")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Signature.areExactMatch(
|
||||
p.getSigningDetails(), new Signature[]{MICROG_REAL_SIGNATURE})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// %s: accept project-signed Phonesky (AXP patch-playstore + our JKS)
|
||||
return p.getPackageName().equals("com.android.vending")
|
||||
&& Signature.areExactMatch(
|
||||
p.getSigningDetails(), new Signature[]{SUNFISH_PHONESKY_SIGNATURE});
|
||||
}""" % MARKER
|
||||
|
||||
if old_is not in text:
|
||||
raise SystemExit("isMicrogSigned block not found exactly")
|
||||
text = text.replace(old_is, new_is, 1)
|
||||
|
||||
old_gen = """ private static Optional<Signature> generateFakeSignature(AndroidPackage p) {
|
||||
if (!isMicrogSigned(p)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Bundle metadata = p.getMetaData();
|
||||
if (metadata == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String fakeSignatureStr = metadata.getString("fake-signature");
|
||||
if (TextUtils.isEmpty(fakeSignatureStr)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Only MICROG_FAKE_SIGNATURE can be faked
|
||||
Signature fakeSignature = new Signature(fakeSignatureStr);
|
||||
if (!fakeSignature.equals(MICROG_FAKE_SIGNATURE)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(fakeSignature);
|
||||
}"""
|
||||
|
||||
new_gen = """ private boolean requestsFakeSignature(AndroidPackage p) {
|
||||
return p.getMetaData() != null
|
||||
&& p.getMetaData().getString("fake-signature") != null;
|
||||
}
|
||||
|
||||
private Optional<Signature> generateFakeSignature(AndroidPackage p,
|
||||
Set<String> permissions) {
|
||||
// %s: EXTENDROM global gate (Developer Options)
|
||||
try {
|
||||
if (android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
android.provider.Settings.Secure.ALLOW_SIGNATURE_FAKE, 0) == 0) {
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Slog.w(TAG, "allow_signature_fake read failed", t);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!isMicrogSigned(p)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// EXTENDROM: require FAKE_PACKAGE_SIGNATURE grant (Self-Check path)
|
||||
if (!permissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Bundle metadata = p.getMetaData();
|
||||
if (metadata == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String fakeSignatureStr = metadata.getString("fake-signature");
|
||||
if (TextUtils.isEmpty(fakeSignatureStr)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Only MICROG_FAKE_SIGNATURE (platform Google) can be faked
|
||||
Signature fakeSignature = new Signature(fakeSignatureStr);
|
||||
if (!fakeSignature.equals(MICROG_FAKE_SIGNATURE)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(fakeSignature);
|
||||
}""" % MARKER
|
||||
|
||||
if old_gen not in text:
|
||||
raise SystemExit("generateFakeSignature block not found exactly")
|
||||
text = text.replace(old_gen, new_gen, 1)
|
||||
|
||||
old_perm = """ // Compute granted permissions only if package has requested permissions
|
||||
final Set<String> grantedPermissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
|
||||
|| ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
|
||||
: mPermissionManager.getGrantedPermissions(ps.getPackageName(), userId);"""
|
||||
|
||||
new_perm = """ // Compute granted permissions only if package has requested permissions
|
||||
// SUNFISH_A16_005_SIGSPOOF: also when fake-signature meta present (need grant check)
|
||||
final Set<String> grantedPermissions = (((flags & PackageManager.GET_PERMISSIONS) == 0
|
||||
&& !requestsFakeSignature(p))
|
||||
|| ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
|
||||
: mPermissionManager.getGrantedPermissions(ps.getPackageName(), userId);"""
|
||||
|
||||
if old_perm not in text:
|
||||
raise SystemExit("grantedPermissions block not found")
|
||||
text = text.replace(old_perm, new_perm, 1)
|
||||
|
||||
old_call = "generateFakeSignature(p).ifPresent(fakeSignature -> {"
|
||||
new_call = "generateFakeSignature(p, grantedPermissions).ifPresent(fakeSignature -> {"
|
||||
if old_call not in text:
|
||||
raise SystemExit("generateFakeSignature call site not found")
|
||||
text = text.replace(old_call, new_call, 1)
|
||||
|
||||
path.write_text(text)
|
||||
print("ComputerEngine: patched OK")
|
||||
|
||||
|
||||
def patch_settings_secure() -> None:
|
||||
path = TREE / "frameworks/base/core/java/android/provider/Settings.java"
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("Settings.java: already patched")
|
||||
return
|
||||
backup(path)
|
||||
needle = (
|
||||
' public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";\n'
|
||||
"\n"
|
||||
" /**\n"
|
||||
" * A flag to tell {@link com.android.server.devicepolicy.DevicePolicyManagerService} that\n"
|
||||
" * the default for {@link #INSTALL_NON_MARKET_APPS} is reversed for this user on OTA. So it\n"
|
||||
)
|
||||
insert = (
|
||||
' public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";\n'
|
||||
"\n"
|
||||
" /**\n"
|
||||
" * %s / EXTENDROM: whether applications can fake a signature.\n"
|
||||
" *\n"
|
||||
" * <p>1 = permit apps to fake signature\n"
|
||||
" * <p>0 = disable this feature\n"
|
||||
" * @hide\n"
|
||||
" */\n"
|
||||
' public static final String ALLOW_SIGNATURE_FAKE = "allow_signature_fake";\n'
|
||||
"\n"
|
||||
" /**\n"
|
||||
" * A flag to tell {@link com.android.server.devicepolicy.DevicePolicyManagerService} that\n"
|
||||
" * the default for {@link #INSTALL_NON_MARKET_APPS} is reversed for this user on OTA. So it\n"
|
||||
) % MARKER
|
||||
if needle not in text:
|
||||
raise SystemExit("Settings.java insertion point not found")
|
||||
path.write_text(text.replace(needle, insert, 1))
|
||||
print("Settings.java: patched OK")
|
||||
|
||||
|
||||
def patch_android_manifest() -> None:
|
||||
path = TREE / "frameworks/base/core/res/AndroidManifest.xml"
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("AndroidManifest: already patched")
|
||||
return
|
||||
backup(path)
|
||||
m = re.search(
|
||||
r'( <permission-group android:name="android\.permission-group\.UNDEFINED"[\s\S]*?/>\s*)',
|
||||
text,
|
||||
)
|
||||
if not m:
|
||||
m = re.search(
|
||||
r'( <permission-group android:name="android\.permission-group\.UNDEFINED"[^>]*>[\s\S]*?</permission-group>\s*)',
|
||||
text,
|
||||
)
|
||||
if not m:
|
||||
raise SystemExit("UNDEFINED permission-group not found")
|
||||
|
||||
block = (
|
||||
m.group(1)
|
||||
+ "\n"
|
||||
+ " <!-- %s / EXTENDROM: signature spoofing -->\n" % MARKER
|
||||
+ ' <permission-group android:name="android.permission-group.FAKE_PACKAGE"\n'
|
||||
+ ' android:label="@string/permgrouplab_fake_package_signature"\n'
|
||||
+ ' android:description="@string/permgrouprequest_fake_package_signature"\n'
|
||||
+ ' android:request="@string/permgrouprequest_fake_package_signature"\n'
|
||||
+ ' android:priority="100" />\n'
|
||||
+ "\n"
|
||||
+ ' <permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE"\n'
|
||||
+ ' android:permissionGroup="android.permission-group.UNDEFINED"\n'
|
||||
+ ' android:protectionLevel="dangerous"\n'
|
||||
+ ' android:label="@string/permlab_fakePackageSignature"\n'
|
||||
+ ' android:description="@string/permdesc_fakePackageSignature" />\n'
|
||||
+ "\n"
|
||||
)
|
||||
text = text[: m.start()] + block + text[m.end() :]
|
||||
path.write_text(text)
|
||||
print("AndroidManifest: patched OK")
|
||||
|
||||
|
||||
def patch_framework_strings() -> None:
|
||||
path = TREE / "frameworks/base/core/res/res/values/strings.xml"
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("framework strings: already patched")
|
||||
return
|
||||
backup(path)
|
||||
addition = (
|
||||
"\n"
|
||||
" <!-- %s / EXTENDROM signature spoofing -->\n"
|
||||
' <string name="permlab_fakePackageSignature">Spoof package signature</string>\n'
|
||||
' <string name="permdesc_fakePackageSignature">Allows applications to impersonate another application (known as \\"signature spoofing\\").</string>\n'
|
||||
' <string name="permgrouplab_fake_package_signature">Spoof package signature</string>\n'
|
||||
' <string name="permgrouprequest_fake_package_signature">Spoof package signature</string>\n'
|
||||
) % MARKER
|
||||
if "</resources>" not in text:
|
||||
raise SystemExit("framework strings: no </resources>")
|
||||
path.write_text(text.replace("</resources>", addition + "</resources>", 1))
|
||||
print("framework strings: patched OK")
|
||||
|
||||
|
||||
def patch_api_current() -> None:
|
||||
path = TREE / "frameworks/base/core/api/current.txt"
|
||||
text = path.read_text()
|
||||
if "FAKE_PACKAGE_SIGNATURE" in text:
|
||||
print("current.txt: already has FAKE_PACKAGE_SIGNATURE")
|
||||
return
|
||||
backup(path)
|
||||
text2 = text.replace(
|
||||
' field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";\n',
|
||||
' field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";\n'
|
||||
' field public static final String FAKE_PACKAGE_SIGNATURE = "android.permission.FAKE_PACKAGE_SIGNATURE";\n',
|
||||
1,
|
||||
)
|
||||
if 'field public static final String FAKE_PACKAGE = "android.permission-group.FAKE_PACKAGE";' not in text2:
|
||||
text2 = text2.replace(
|
||||
' field public static final String CONTACTS = "android.permission-group.CONTACTS";\n',
|
||||
' field public static final String CONTACTS = "android.permission-group.CONTACTS";\n'
|
||||
' field public static final String FAKE_PACKAGE = "android.permission-group.FAKE_PACKAGE";\n',
|
||||
1,
|
||||
)
|
||||
if text2 == text:
|
||||
raise SystemExit("current.txt: failed to insert")
|
||||
path.write_text(text2)
|
||||
print("current.txt: patched OK")
|
||||
|
||||
|
||||
def patch_lint_baseline() -> None:
|
||||
path = TREE / "frameworks/base/core/api/lint-baseline.txt"
|
||||
text = path.read_text()
|
||||
if "FAKE_PACKAGE_SIGNATURE" in text:
|
||||
print("lint-baseline: already patched")
|
||||
return
|
||||
backup(path)
|
||||
addition = """UnflaggedApi: android.Manifest.permission#FAKE_PACKAGE_SIGNATURE:
|
||||
New API must be flagged with @FlaggedApi: field android.Manifest.permission.FAKE_PACKAGE_SIGNATURE
|
||||
UnflaggedApi: android.Manifest.permission_group#FAKE_PACKAGE:
|
||||
New API must be flagged with @FlaggedApi: field android.Manifest.permission_group.FAKE_PACKAGE
|
||||
"""
|
||||
path.write_text(text + addition)
|
||||
print("lint-baseline: patched OK")
|
||||
|
||||
|
||||
def patch_activity() -> None:
|
||||
path = TREE / "frameworks/base/core/java/android/app/Activity.java"
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("Activity.java: already patched")
|
||||
return
|
||||
backup(path)
|
||||
needle = """ final PackageManager packageManager = context.getPackageManager();
|
||||
final Intent intent = packageManager.buildRequestPermissionsIntent(permissions);
|
||||
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
|
||||
mHasCurrentPermissionsRequest = true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private int[] getPermissionRequestStates(@NonNull Context deviceContext,
|
||||
"""
|
||||
insert = """ final PackageManager packageManager = context.getPackageManager();
|
||||
|
||||
// %s / EXTENDROM: deny FAKE_PACKAGE dialog when spoofing toggle off
|
||||
java.util.List<String> permlist = java.util.Arrays.asList(permissions);
|
||||
if (permlist.contains("android.permission.FAKE_PACKAGE_SIGNATURE")) {
|
||||
if (android.provider.Settings.Secure.getInt(getContentResolver(),
|
||||
android.provider.Settings.Secure.ALLOW_SIGNATURE_FAKE, 0) == 0) {
|
||||
Log.w(TAG, "FAKE_PACKAGE_SIGNATURE denied: allow_signature_fake is off");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Intent intent = packageManager.buildRequestPermissionsIntent(permissions);
|
||||
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
|
||||
mHasCurrentPermissionsRequest = true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private int[] getPermissionRequestStates(@NonNull Context deviceContext,
|
||||
""" % MARKER
|
||||
if needle not in text:
|
||||
raise SystemExit("Activity.java insertion point not found")
|
||||
path.write_text(text.replace(needle, insert, 1))
|
||||
print("Activity.java: patched OK")
|
||||
|
||||
|
||||
def patch_permission_mapping() -> None:
|
||||
path = (
|
||||
TREE
|
||||
/ "packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt"
|
||||
)
|
||||
text = path.read_text()
|
||||
if MARKER in text:
|
||||
print("PermissionMapping: already patched")
|
||||
return
|
||||
backup(path)
|
||||
needle = "PLATFORM_PERMISSIONS[Manifest.permission.BODY_SENSORS] = Manifest.permission_group.SENSORS"
|
||||
addition = (
|
||||
"\n\n // %s\n"
|
||||
" PLATFORM_PERMISSIONS[Manifest.permission.FAKE_PACKAGE_SIGNATURE] ="
|
||||
" Manifest.permission_group.FAKE_PACKAGE" % MARKER
|
||||
)
|
||||
if needle in text:
|
||||
text = text.replace(needle, needle + addition, 1)
|
||||
else:
|
||||
needle2 = (
|
||||
"PLATFORM_PERMISSIONS[Manifest.permission.GET_ACCOUNTS] = Manifest.permission_group.CONTACTS"
|
||||
)
|
||||
if needle2 not in text:
|
||||
raise SystemExit("PermissionMapping insertion point not found")
|
||||
text = text.replace(needle2, needle2 + addition, 1)
|
||||
path.write_text(text)
|
||||
print("PermissionMapping: patched OK")
|
||||
|
||||
|
||||
def patch_settings_app() -> None:
|
||||
dash = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java"
|
||||
)
|
||||
text = dash.read_text()
|
||||
if MARKER not in text:
|
||||
backup(dash)
|
||||
needle = " controllers.add(new SensitiveContentProtectionPreferenceController(context));\n"
|
||||
if needle not in text:
|
||||
raise SystemExit("Dashboard insertion not found")
|
||||
text = text.replace(
|
||||
needle,
|
||||
needle
|
||||
+ " // %s\n" % MARKER
|
||||
+ " controllers.add(new SpoofSignaturePreferenceController(context));\n"
|
||||
+ " controllers.add(new SpoofSignatureInfo(context));\n",
|
||||
1,
|
||||
)
|
||||
dash.write_text(text)
|
||||
print("Settings dashboard: patched OK")
|
||||
else:
|
||||
print("Settings dashboard: already patched")
|
||||
|
||||
ctrl = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/development/SpoofSignaturePreferenceController.java"
|
||||
)
|
||||
if not ctrl.exists():
|
||||
ctrl.write_text(
|
||||
"""/*
|
||||
* Copyright (C) 2019-2024 steadfasterX <steadfasterX |AT| binbash #DOT# rocks>
|
||||
* LICENSE: GNU General Public License v3.0
|
||||
* Ported to LOS 23.2 / sunfish-a16-rom (%s).
|
||||
*/
|
||||
|
||||
package com.android.settings.development;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
||||
|
||||
public class SpoofSignaturePreferenceController extends DeveloperOptionsPreferenceController
|
||||
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
|
||||
|
||||
private static final String ALLOW_SIGNATURE_FAKE_KEY = "allow_signature_fake";
|
||||
|
||||
@VisibleForTesting
|
||||
static final int SETTING_VALUE_ON = 1;
|
||||
@VisibleForTesting
|
||||
static final int SETTING_VALUE_OFF = 0;
|
||||
|
||||
public SpoofSignaturePreferenceController(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return ALLOW_SIGNATURE_FAKE_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean isEnabled = (Boolean) newValue;
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ALLOW_SIGNATURE_FAKE,
|
||||
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
final int spoofingMode = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ALLOW_SIGNATURE_FAKE, SETTING_VALUE_OFF);
|
||||
|
||||
((SwitchPreference) mPreference).setChecked(spoofingMode != SETTING_VALUE_OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchDisabled() {
|
||||
super.onDeveloperOptionsSwitchDisabled();
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ALLOW_SIGNATURE_FAKE, SETTING_VALUE_OFF);
|
||||
((SwitchPreference) mPreference).setChecked(false);
|
||||
}
|
||||
}
|
||||
"""
|
||||
% MARKER
|
||||
)
|
||||
print("SpoofSignaturePreferenceController: written")
|
||||
|
||||
info = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/development/SpoofSignatureInfo.java"
|
||||
)
|
||||
if not info.exists():
|
||||
info.write_text(
|
||||
"""/*
|
||||
* Copyright (C) 2019-2024 steadfasterX <steadfasterX |AT| binbash #DOT# rocks>
|
||||
* LICENSE: GNU General Public License v3.0
|
||||
* Ported to LOS 23.2 / sunfish-a16-rom (%s).
|
||||
*/
|
||||
|
||||
package com.android.settings.development;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.preference.Preference;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
||||
|
||||
public class SpoofSignatureInfo extends DeveloperOptionsPreferenceController
|
||||
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
|
||||
|
||||
private static final String ALLOW_SIGNATURE_FAKE_KEY_INFO = "allow_signature_fake_info";
|
||||
|
||||
public SpoofSignatureInfo(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return ALLOW_SIGNATURE_FAKE_KEY_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
"""
|
||||
% MARKER
|
||||
)
|
||||
print("SpoofSignatureInfo: written")
|
||||
|
||||
xml = TREE / "packages/apps/Settings/res/xml/development_settings.xml"
|
||||
xtext = xml.read_text()
|
||||
if MARKER not in xtext:
|
||||
backup(xml)
|
||||
needle = """ android:key="development_prefs_screen"
|
||||
android:title="@string/development_settings_title">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="debug_misc_category"
|
||||
"""
|
||||
insert = """ android:key="development_prefs_screen"
|
||||
android:title="@string/development_settings_title">
|
||||
|
||||
<!-- %s / EXTENDROM signature spoofing -->
|
||||
<PreferenceCategory
|
||||
android:key="signature_spoof_category"
|
||||
android:title="@string/signature_spoof_category"
|
||||
android:order="9999">
|
||||
|
||||
<Preference
|
||||
android:key="allow_signature_fake_info"
|
||||
android:summary="@string/allow_signature_fake_details" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="allow_signature_fake"
|
||||
android:title="@string/allow_signature_fake"
|
||||
android:summary="@string/allow_signature_fake_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="debug_misc_category"
|
||||
""" % MARKER
|
||||
if needle not in xtext:
|
||||
raise SystemExit("development_settings.xml insertion not found")
|
||||
xml.write_text(xtext.replace(needle, insert, 1))
|
||||
print("development_settings.xml: patched OK")
|
||||
else:
|
||||
print("development_settings.xml: already patched")
|
||||
|
||||
sxml = TREE / "packages/apps/Settings/res/values/strings.xml"
|
||||
stext = sxml.read_text()
|
||||
if MARKER not in stext:
|
||||
backup(sxml)
|
||||
addition = (
|
||||
"\n"
|
||||
" <!-- %s / EXTENDROM signature spoofing -->\n"
|
||||
' <string name="signature_spoof_category">Signature spoofing support</string>\n'
|
||||
' <string name="allow_signature_fake">Allow signature spoofing</string>\n'
|
||||
' <string name="allow_signature_fake_summary">If disabled, any previously granted signature spoofing permissions remain in place, but no longer have any effect</string>\n'
|
||||
' <string name="allow_signature_fake_details">Allows applications to impersonate another application (known as \\"signature spoofing\\").\\n\\nLegitimate applications include microG or Phonesky (Google Play Store for microG).\\n\\nThis option is a global ON/OFF setting, i.e. applications must explicitly request signature spoofing, or it must be manually enabled within each App\\\'s \\"Permission\\" screen (this permission can also be revoked there).</string>\n'
|
||||
) % MARKER
|
||||
sxml.write_text(stext.replace("</resources>", addition + "</resources>", 1))
|
||||
print("Settings strings: patched OK")
|
||||
else:
|
||||
print("Settings strings: already patched")
|
||||
|
||||
def main() -> None:
|
||||
if not PHONESKY_HEX or len(PHONESKY_HEX) < 100:
|
||||
raise SystemExit("phonesky-cert.hex missing/short")
|
||||
print("Phonesky cert hex len=%d" % len(PHONESKY_HEX))
|
||||
patch_computer_engine()
|
||||
patch_settings_secure()
|
||||
patch_android_manifest()
|
||||
patch_framework_strings()
|
||||
patch_api_current()
|
||||
patch_lint_baseline()
|
||||
patch_activity()
|
||||
patch_permission_mapping()
|
||||
patch_settings_app()
|
||||
print("ALL DONE")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user