improve profile isolation
This commit is contained in:
@@ -87,14 +87,75 @@ class _Filesystem {
|
||||
|
||||
Future<void> _linkMozillaDir(Directory filesDir) async {
|
||||
final mozillaDir = Directory(p.join(selectedProfileDir.path, 'mozilla'));
|
||||
await mozillaDir.create();
|
||||
await mozillaDir.create(recursive: true);
|
||||
|
||||
final mozillaLink = Link(p.join(filesDir.path, 'mozilla'));
|
||||
if (await mozillaLink.exists()) {
|
||||
await mozillaLink.delete();
|
||||
final mozillaPath = p.join(filesDir.path, 'mozilla');
|
||||
|
||||
Future<void> moveAside(FileSystemEntityType type) async {
|
||||
final backupPath = p.join(
|
||||
filesDir.path,
|
||||
'mozilla.backup.${DateTime.now().millisecondsSinceEpoch}',
|
||||
);
|
||||
|
||||
if (type == FileSystemEntityType.directory) {
|
||||
await Directory(mozillaPath).rename(backupPath);
|
||||
} else {
|
||||
await File(mozillaPath).rename(backupPath);
|
||||
}
|
||||
}
|
||||
|
||||
await mozillaLink.create(mozillaDir.path);
|
||||
Future<void> createLink() async {
|
||||
await Link(mozillaPath).create(mozillaDir.path);
|
||||
}
|
||||
|
||||
final currentType = await FileSystemEntity.type(
|
||||
mozillaPath,
|
||||
followLinks: false,
|
||||
);
|
||||
|
||||
switch (currentType) {
|
||||
case FileSystemEntityType.notFound:
|
||||
break;
|
||||
case FileSystemEntityType.link:
|
||||
final link = Link(mozillaPath);
|
||||
try {
|
||||
if (await link.target() == mozillaDir.path) {
|
||||
return;
|
||||
}
|
||||
} on FileSystemException {
|
||||
// Replace unreadable or broken links.
|
||||
}
|
||||
|
||||
await link.delete();
|
||||
case FileSystemEntityType.directory:
|
||||
case FileSystemEntityType.file:
|
||||
case FileSystemEntityType.unixDomainSock:
|
||||
case FileSystemEntityType.pipe:
|
||||
default:
|
||||
await moveAside(currentType);
|
||||
}
|
||||
|
||||
try {
|
||||
await createLink();
|
||||
} on PathExistsException {
|
||||
final retryType = await FileSystemEntity.type(
|
||||
mozillaPath,
|
||||
followLinks: false,
|
||||
);
|
||||
|
||||
if (retryType == FileSystemEntityType.link) {
|
||||
final link = Link(mozillaPath);
|
||||
if (await link.target() == mozillaDir.path) {
|
||||
return;
|
||||
}
|
||||
|
||||
await link.delete();
|
||||
} else if (retryType != FileSystemEntityType.notFound) {
|
||||
await moveAside(retryType);
|
||||
}
|
||||
|
||||
await createLink();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setupSqliteCache() async {
|
||||
|
||||
+3
-1
@@ -150,7 +150,9 @@ object GlobalComponents {
|
||||
|
||||
//RustHttpConfig.setClient(lazy { newComponents.core.client })
|
||||
|
||||
newComponents.core.engine.warmUp()
|
||||
if (mode == ComponentsMode.FULL) {
|
||||
newComponents.core.engine.warmUp()
|
||||
}
|
||||
|
||||
fun restorePreviousCustomTabs() {
|
||||
if (previousCustomTabs.isEmpty()) return
|
||||
|
||||
+4
@@ -57,6 +57,10 @@ class ProfileContext(private val base: Context, val relativePath: String) :
|
||||
return customApplicationInfo
|
||||
}
|
||||
|
||||
override fun getApplicationContext(): Context {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getFilesDir(): File {
|
||||
return customFilesDir
|
||||
}
|
||||
|
||||
+3
-4
@@ -303,15 +303,14 @@ class IntentReceiverActivity : Activity() {
|
||||
contextId: String?,
|
||||
) {
|
||||
val message = "This PWA was originally installed in a different profile. " +
|
||||
"Opening it here will use your current profile's data and settings, " +
|
||||
"which means you won't see the same content, preferences, or saved data " +
|
||||
"that you had in the original profile.\n\n" +
|
||||
"Opening it here uses only your current profile's data and settings. " +
|
||||
"The original profile's app state and saved data will not be used.\n\n" +
|
||||
"Do you want to proceed anyway?"
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("PWA Profile Mismatch")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("Open Anyway") { _, _ ->
|
||||
.setPositiveButton("Open in Current Profile") { _, _ ->
|
||||
Log.d(TAG, "User chose to open PWA despite profile mismatch")
|
||||
launchPwaWithContext(url, contextId)
|
||||
}
|
||||
|
||||
+4
-4
@@ -144,7 +144,7 @@ class GeckoPwaApiImpl(
|
||||
|
||||
val (iconBitmap, isMaskable) = loadPwaIcon(manifest)
|
||||
|
||||
val shortcutId = generateShortcutId(manifest.startUrl)
|
||||
val shortcutId = generateShortcutId(manifest.startUrl, profileUuid)
|
||||
val launchToken = resolveLaunchToken(
|
||||
shortcutManager = shortcutManager,
|
||||
shortcutId = shortcutId,
|
||||
@@ -189,11 +189,11 @@ class GeckoPwaApiImpl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a collision-resistant shortcut ID from a URL using SHA-256.
|
||||
* Generates a collision-resistant shortcut ID from URL + profile using SHA-256.
|
||||
*/
|
||||
private fun generateShortcutId(url: String): String {
|
||||
private fun generateShortcutId(url: String, profileUuid: String): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val hash = digest.digest(url.toByteArray())
|
||||
val hash = digest.digest("$url::$profileUuid".toByteArray())
|
||||
val hex = hash.take(16).joinToString("") { "%02x".format(it) }
|
||||
return "pwa_$hex"
|
||||
}
|
||||
|
||||
+2
-4
@@ -232,9 +232,7 @@ class Core(
|
||||
*/
|
||||
val customTabsStore by lazy { CustomTabsServiceStore() }
|
||||
|
||||
// Must use the base application context (not ProfileContext) so the database
|
||||
// matches what WebAppLauncherActivity (from the library) uses when loading manifests.
|
||||
val webAppManifestStorage by lazy { ManifestStorage(context.applicationContext) }
|
||||
val webAppManifestStorage by lazy { ManifestStorage(context) }
|
||||
|
||||
val webAppShortcutManager by lazy {
|
||||
WebAppShortcutManager(context, client, webAppManifestStorage)
|
||||
@@ -288,4 +286,4 @@ class Core(
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user