diff --git a/client/config.xml b/client/config.xml
index 2162e2eac7..4befc0fc18 100644
--- a/client/config.xml
+++ b/client/config.xml
@@ -23,7 +23,7 @@
-
+
diff --git a/client/src/cordova/android/OutlineAndroidLib/outline/src/main/java/org/outline/vpn/VpnTunnelService.java b/client/src/cordova/android/OutlineAndroidLib/outline/src/main/java/org/outline/vpn/VpnTunnelService.java
index 8a2f6e1016..732db1efdf 100644
--- a/client/src/cordova/android/OutlineAndroidLib/outline/src/main/java/org/outline/vpn/VpnTunnelService.java
+++ b/client/src/cordova/android/OutlineAndroidLib/outline/src/main/java/org/outline/vpn/VpnTunnelService.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -379,6 +380,8 @@ private void broadcastVpnConnectivityChange(TunnelStatus status) {
}
Intent statusChange = new Intent(STATUS_BROADCAST_KEY);
statusChange.addCategory(getPackageName());
+ // We must explicitly set the package for security reasons: https://developer.android.com/about/versions/14/behavior-changes-14#security
+ statusChange.setPackage(this.getPackageName());
statusChange.putExtra(MessageData.PAYLOAD.value, status.value);
statusChange.putExtra(MessageData.TUNNEL_ID.value, tunnelConfig.id);
sendBroadcast(statusChange);
@@ -448,7 +451,9 @@ private void startForegroundWithNotification(final String serverName) {
notificationBuilder = getNotificationBuilder(serverName);
}
notificationBuilder.setContentText(getStringResource("connected_server_state"));
- startForeground(NOTIFICATION_SERVICE_ID, notificationBuilder.build());
+
+ // We must specify the service type for security reasons: https://developer.android.com/about/versions/14/changes/fgs-types-required
+ startForeground(NOTIFICATION_SERVICE_ID, notificationBuilder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
} catch (Exception e) {
LOG.warning("Unable to display persistent notification");
}
diff --git a/client/src/cordova/apple/xcode/ios/Outline.xcodeproj/project.pbxproj b/client/src/cordova/apple/xcode/ios/Outline.xcodeproj/project.pbxproj
index 650e822325..512bebb378 100755
--- a/client/src/cordova/apple/xcode/ios/Outline.xcodeproj/project.pbxproj
+++ b/client/src/cordova/apple/xcode/ios/Outline.xcodeproj/project.pbxproj
@@ -21,7 +21,7 @@
5F7F90AE0E924FD7B065C415 /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 0394302BA6114B2AB648D4FF /* CDVStatusBar.m */; };
65A9AC9C2BEC091700C5899F /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 65A9AC9B2BEC091700C5899F /* PrivacyInfo.xcprivacy */; };
6AFF5BF91D6E424B00AB3073 /* CDVLaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */; };
- A246B7E52B07AADD00ECACD5 /* AppKitIntegration.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A246B7DD2B07AACF00ECACD5 /* AppKitIntegration.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ A246B7E52B07AADD00ECACD5 /* AppKitIntegration.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A246B7DD2B07AACF00ECACD5 /* AppKitIntegration.framework */; platformFilter = maccatalyst; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A25FB7DC2B0D4420009B6B5F /* AppKitIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = A272490D2B0D20530018A598 /* AppKitIntegration.h */; settings = {ATTRIBUTES = (Public, ); }; };
A271D42D2A708240009981B2 /* AppDelegate+Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = A271D42C2A708240009981B2 /* AppDelegate+Outline.m */; };
A271D4342A70829D009981B2 /* OutlineAppleLib in Frameworks */ = {isa = PBXBuildFile; productRef = A271D4332A70829D009981B2 /* OutlineAppleLib */; };
@@ -692,6 +692,7 @@
};
A246B7E72B07AADD00ECACD5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
+ platformFilter = maccatalyst;
target = A246B7DC2B07AACF00ECACD5 /* AppKitIntegration */;
targetProxy = A246B7E62B07AADD00ECACD5 /* PBXContainerItemProxy */;
};
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-1024.png
deleted file mode 100644
index 1b2c3fffb5..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-1024.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-128.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-128.png
deleted file mode 100644
index 8404b66d9f..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-128.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-16.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-16.png
deleted file mode 100644
index 0babf3728f..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-16.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-256.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-256.png
deleted file mode 100644
index b272c20ce9..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-256.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-32.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-32.png
deleted file mode 100644
index c80d6bc1ca..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-32.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-512.png b/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-512.png
deleted file mode 100644
index 6eff93b62c..0000000000
Binary files a/client/src/cordova/apple/xcode/ios/Outline/Assets.xcassets/AppIcon.appiconset/icon-512.png and /dev/null differ
diff --git a/client/src/cordova/apple/xcode/macos/Outline/config.xml b/client/src/cordova/apple/xcode/macos/Outline/config.xml
index d8819571b9..d24f8d1aa4 100755
--- a/client/src/cordova/apple/xcode/macos/Outline/config.xml
+++ b/client/src/cordova/apple/xcode/macos/Outline/config.xml
@@ -51,8 +51,8 @@
-
-
+
+
diff --git a/client/src/cordova/build.action.mjs b/client/src/cordova/build.action.mjs
index 863ea3be41..13ddb63b58 100644
--- a/client/src/cordova/build.action.mjs
+++ b/client/src/cordova/build.action.mjs
@@ -38,7 +38,9 @@ export async function main(...parameters) {
await runAction('client/src/cordova/setup', ...parameters);
if (verbose) {
- cordova.on('verbose', message => console.debug(`[cordova:verbose] ${message}`));
+ cordova.on('verbose', message =>
+ console.debug(`[cordova:verbose] ${message}`)
+ );
}
// this is so cordova doesn't complain about not being in a cordova project
@@ -49,10 +51,17 @@ export async function main(...parameters) {
return androidDebug(verbose);
case 'android' + 'release':
if (!process.env.JAVA_HOME) {
- throw new ReferenceError('JAVA_HOME must be defined in the environment to build an Android Release!');
+ throw new ReferenceError(
+ 'JAVA_HOME must be defined in the environment to build an Android Release!'
+ );
}
- if (!(process.env.ANDROID_KEY_STORE_PASSWORD && process.env.ANDROID_KEY_STORE_CONTENTS)) {
+ if (
+ !(
+ process.env.ANDROID_KEY_STORE_PASSWORD &&
+ process.env.ANDROID_KEY_STORE_CONTENTS
+ )
+ ) {
throw new ReferenceError(
"Both 'ANDROID_KEY_STORE_PASSWORD' and 'ANDROID_KEY_STORE_CONTENTS' must be defined in the environment to build an Android Release!"
);
@@ -94,7 +103,14 @@ function getXcodeBuildArgs(platform) {
}
return [
'-workspace',
- path.join(getRootDir(), 'client', 'src', 'cordova', 'apple', workspaceFilename),
+ path.join(
+ getRootDir(),
+ 'client',
+ 'src',
+ 'cordova',
+ 'apple',
+ workspaceFilename
+ ),
'-scheme',
'Outline',
'-destination',
@@ -103,7 +119,9 @@ function getXcodeBuildArgs(platform) {
}
async function appleDebug(platform) {
- console.warn(`WARNING: building "${platform}" in [DEBUG] mode. Do not publish this build!!`);
+ console.warn(
+ `WARNING: building "${platform}" in [DEBUG] mode. Do not publish this build!!`
+ );
return spawnStream(
'xcodebuild',
@@ -118,11 +136,20 @@ async function appleDebug(platform) {
}
async function appleRelease(platform) {
- return spawnStream('xcodebuild', 'clean', ...getXcodeBuildArgs(platform), 'archive', '-configuration', 'Release');
+ return spawnStream(
+ 'xcodebuild',
+ 'clean',
+ ...getXcodeBuildArgs(platform),
+ 'archive',
+ '-configuration',
+ 'Release'
+ );
}
async function androidDebug(verbose) {
- console.warn(`WARNING: building "android" in [DEBUG] mode. Do not publish this build!!`);
+ console.warn(
+ 'WARNING: building "android" in [DEBUG] mode. Do not publish this build!!'
+ );
return cordova.compile({
verbose,
@@ -142,7 +169,12 @@ const JAVA_BUNDLETOOL_VERSION = '1.8.2';
const JAVA_BUNDLETOOL_RESOURCE_URL = `https://github.com/google/bundletool/releases/download/1.8.2/bundletool-all-${JAVA_BUNDLETOOL_VERSION}.jar`;
async function androidRelease(ksPassword, ksContents, javaPath, verbose) {
- const androidBuildPath = path.resolve(getRootDir(), 'platforms', 'android');
+ const androidBuildPath = path.resolve(
+ getRootDir(),
+ 'client',
+ 'platforms',
+ 'android'
+ );
const keystorePath = path.resolve(androidBuildPath, 'keystore.p12');
await fs.writeFile(keystorePath, Buffer.from(ksContents, 'base64'));
@@ -176,7 +208,15 @@ async function androidRelease(ksPassword, ksContents, javaPath, verbose) {
'-jar',
bundletoolPath,
'build-apks',
- `--bundle=${path.resolve(androidBuildPath, 'app', 'build', 'outputs', 'bundle', 'release', 'app-release.aab')}`,
+ `--bundle=${path.resolve(
+ androidBuildPath,
+ 'app',
+ 'build',
+ 'outputs',
+ 'bundle',
+ 'release',
+ 'app-release.aab'
+ )}`,
`--output=${outputPath}`,
'--mode=universal',
`--ks=${keystorePath}`,
diff --git a/client/src/cordova/plugin/plugin.xml b/client/src/cordova/plugin/plugin.xml
index 9e0e871804..2dac7b6fc9 100644
--- a/client/src/cordova/plugin/plugin.xml
+++ b/client/src/cordova/plugin/plugin.xml
@@ -38,11 +38,13 @@
+