From ad83de97b013ff8c5324a38338aedd38a97ccf7d Mon Sep 17 00:00:00 2001
From: Adrian Castro <22133246+castdrian@users.noreply.github.com>
Date: Fri, 16 Aug 2024 11:25:43 +0200
Subject: [PATCH] refactor: rewrite certificate check module to be more
detailed
---
.gitignore | 8 +--
.../check-ios-app-id/expo-module.config.json | 6 +++
apps/expo/modules/check-ios-app-id/index.ts | 9 ++++
.../ios/CheckIosAppId.podspec} | 6 +--
.../ios/CheckIosAppIdModule.swift | 54 +++++++++++++++++++
.../src/CheckIosAppIdModule.android.ts | 10 ++++
.../src/CheckIosAppIdModule.ts} | 7 ++-
.../expo-module.config.json | 6 ---
.../modules/check-ios-certificate/index.ts | 11 ----
.../ios/CheckIosCertificateModule.swift | 37 -------------
.../src/CheckIosCertificateModule.android.ts | 10 ----
.../modules/check-ios-marketplace/index.ts | 20 +------
.../src/CheckIosMarketplaceModule.ts | 19 ++++++-
apps/expo/package.json | 2 +-
apps/expo/src/app/(tabs)/downloads.tsx | 19 +++----
.../src/components/player/BottomControls.tsx | 14 +++--
16 files changed, 127 insertions(+), 111 deletions(-)
create mode 100644 apps/expo/modules/check-ios-app-id/expo-module.config.json
create mode 100644 apps/expo/modules/check-ios-app-id/index.ts
rename apps/expo/modules/{check-ios-certificate/ios/CheckIosCertificate.podspec => check-ios-app-id/ios/CheckIosAppId.podspec} (71%)
create mode 100644 apps/expo/modules/check-ios-app-id/ios/CheckIosAppIdModule.swift
create mode 100644 apps/expo/modules/check-ios-app-id/src/CheckIosAppIdModule.android.ts
rename apps/expo/modules/{check-ios-certificate/src/CheckIosCertificateModule.ts => check-ios-app-id/src/CheckIosAppIdModule.ts} (55%)
delete mode 100644 apps/expo/modules/check-ios-certificate/expo-module.config.json
delete mode 100644 apps/expo/modules/check-ios-certificate/index.ts
delete mode 100644 apps/expo/modules/check-ios-certificate/ios/CheckIosCertificateModule.swift
delete mode 100644 apps/expo/modules/check-ios-certificate/src/CheckIosCertificateModule.android.ts
diff --git a/.gitignore b/.gitignore
index 9e9a2e8..3b3865b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,10 +17,10 @@ coverage
dist/
expo-env.d.ts
apps/expo/.gitignore
-ios/
-android/
-!modules/*/ios/
-!modules/*/android/
+
+# Ignore top-level ios and android directories
+apps/expo/ios/
+apps/expo/android/
# production
build
diff --git a/apps/expo/modules/check-ios-app-id/expo-module.config.json b/apps/expo/modules/check-ios-app-id/expo-module.config.json
new file mode 100644
index 0000000..8717dc5
--- /dev/null
+++ b/apps/expo/modules/check-ios-app-id/expo-module.config.json
@@ -0,0 +1,6 @@
+{
+ "platforms": ["ios"],
+ "ios": {
+ "modules": ["CheckIosAppIdModule"]
+ }
+}
diff --git a/apps/expo/modules/check-ios-app-id/index.ts b/apps/expo/modules/check-ios-app-id/index.ts
new file mode 100644
index 0000000..666455b
--- /dev/null
+++ b/apps/expo/modules/check-ios-app-id/index.ts
@@ -0,0 +1,9 @@
+import CheckIosAppIdModule from "./src/CheckIosAppIdModule";
+
+export function isIncorrectAppId(): boolean {
+ return CheckIosAppIdModule.isIncorrectAppId();
+}
+
+export function getAppId(): string {
+ return CheckIosAppIdModule.getAppId();
+}
diff --git a/apps/expo/modules/check-ios-certificate/ios/CheckIosCertificate.podspec b/apps/expo/modules/check-ios-app-id/ios/CheckIosAppId.podspec
similarity index 71%
rename from apps/expo/modules/check-ios-certificate/ios/CheckIosCertificate.podspec
rename to apps/expo/modules/check-ios-app-id/ios/CheckIosAppId.podspec
index 597e515..71d1c58 100644
--- a/apps/expo/modules/check-ios-certificate/ios/CheckIosCertificate.podspec
+++ b/apps/expo/modules/check-ios-app-id/ios/CheckIosAppId.podspec
@@ -1,8 +1,8 @@
Pod::Spec.new do |s|
- s.name = 'CheckIosCertificate'
+ s.name = 'CheckIosAppId'
s.version = '1.0.0'
- s.summary = 'Check if iOS certificate is Development or Production.'
- s.description = 'Check if iOS certificate is Development or Production.'
+ s.summary = 'Check if iOS App ID is explicit or wildcard.'
+ s.description = 'Check if iOS App ID is explicit or wildcard.'
s.author = 'castdrian'
s.homepage = 'https://docs.expo.dev/modules/'
s.platforms = { :ios => '13.4', :tvos => '13.4' }
diff --git a/apps/expo/modules/check-ios-app-id/ios/CheckIosAppIdModule.swift b/apps/expo/modules/check-ios-app-id/ios/CheckIosAppIdModule.swift
new file mode 100644
index 0000000..e0ef1e9
--- /dev/null
+++ b/apps/expo/modules/check-ios-app-id/ios/CheckIosAppIdModule.swift
@@ -0,0 +1,54 @@
+import ExpoModulesCore
+
+public class CheckIosAppIdModule: Module {
+ public func definition() -> ModuleDefinition {
+ Name("CheckIosAppId")
+
+ Function("isIncorrectAppId") { () -> Bool in
+ #if targetEnvironment(simulator)
+ return false
+ #else
+ guard let appId = self.extractAppId() else {
+ return false
+ }
+
+ return appId.hasSuffix(".*") || (Bundle.main.bundleIdentifier != nil && !appId.contains(Bundle.main.bundleIdentifier!))
+ #endif
+ }
+
+ // Function to get the App ID from the provisioning profile
+ Function("getAppId") { () -> String? in
+ #if targetEnvironment(simulator)
+ return nil
+ #else
+ return self.extractAppId()
+ #endif
+ }
+ }
+
+ // Helper function to extract the application-identifier value from the provisioning profile
+ private func extractAppId() -> String? {
+ guard let filePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
+ return nil
+ }
+
+ let fileURL = URL(fileURLWithPath: filePath)
+ do {
+ let data = try String(contentsOf: fileURL, encoding: .ascii)
+ let cleared = data.components(separatedBy: .whitespacesAndNewlines).joined()
+
+ // Search for the application-identifier key and extract its value
+ if let range = cleared.range(of: "application-identifier") {
+ let substring = cleared[range.upperBound...]
+ if let endRange = substring.range(of: "") {
+ let appId = String(substring[.. ModuleDefinition {
- // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
- // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
- // The module will be accessible from `requireNativeModule('CheckIosCertificate')` in JavaScript.
- Name("CheckIosCertificate")
-
- // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
- Function("isDevelopmentProvisioningProfile") { () -> Any in
- #if targetEnvironment(simulator)
- // Running on the Simulator
- return true
- #else
- // Check for provisioning profile for non-Simulator execution
- guard let filePath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
- return false
- }
-
- let fileURL = URL(fileURLWithPath: filePath)
- do {
- let data = try String(contentsOf: fileURL, encoding: .ascii)
- let cleared = data.components(separatedBy: .whitespacesAndNewlines).joined()
- return cleared.contains("get-task-allow")
- } catch {
- // Handling error if the file read fails
- print("Error reading provisioning profile: \(error)")
- return false
- }
- #endif
- }
- }
-}
diff --git a/apps/expo/modules/check-ios-certificate/src/CheckIosCertificateModule.android.ts b/apps/expo/modules/check-ios-certificate/src/CheckIosCertificateModule.android.ts
deleted file mode 100644
index fa041d2..0000000
--- a/apps/expo/modules/check-ios-certificate/src/CheckIosCertificateModule.android.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { UnavailabilityError } from "expo-modules-core";
-
-export default {
- isDevelopmentProvisioningProfile: () => {
- throw new UnavailabilityError(
- "CheckIosCertificate",
- "isDevelopmentProvisioningProfile",
- );
- },
-};
diff --git a/apps/expo/modules/check-ios-marketplace/index.ts b/apps/expo/modules/check-ios-marketplace/index.ts
index 3b5f8c6..c6dd3e1 100644
--- a/apps/expo/modules/check-ios-marketplace/index.ts
+++ b/apps/expo/modules/check-ios-marketplace/index.ts
@@ -1,22 +1,6 @@
+import type { MarketplaceSource } from "./src/CheckIosMarketplaceModule";
import CheckIosMarketplaceModule from "./src/CheckIosMarketplaceModule";
-export enum MarketplaceSource {
- AppStore = "App Store",
- TestFlight = "TestFlight",
- Marketplace = "Alternative marketplace",
- Web = "Website",
- Other = "Other",
- Unknown = "Unknown",
- Error = "Error",
- Unavailable = "Unavailable",
-}
-
-interface CheckIosMarketplaceModule {
- getCurrentMarketplaceAsync(): Promise;
-}
-
export async function getCurrentMarketplaceAsync(): Promise {
- return (
- CheckIosMarketplaceModule as CheckIosMarketplaceModule
- ).getCurrentMarketplaceAsync();
+ return CheckIosMarketplaceModule.getCurrentMarketplaceAsync();
}
diff --git a/apps/expo/modules/check-ios-marketplace/src/CheckIosMarketplaceModule.ts b/apps/expo/modules/check-ios-marketplace/src/CheckIosMarketplaceModule.ts
index 5d729a3..a025047 100644
--- a/apps/expo/modules/check-ios-marketplace/src/CheckIosMarketplaceModule.ts
+++ b/apps/expo/modules/check-ios-marketplace/src/CheckIosMarketplaceModule.ts
@@ -1,5 +1,22 @@
import { requireNativeModule } from "expo-modules-core";
+export enum MarketplaceSource {
+ AppStore = "App Store",
+ TestFlight = "TestFlight",
+ Marketplace = "Alternative marketplace",
+ Web = "Website",
+ Other = "Other",
+ Unknown = "Unknown",
+ Error = "Error",
+ Unavailable = "Unavailable",
+}
+
+interface CheckIosMarketplaceModule {
+ getCurrentMarketplaceAsync(): Promise;
+}
+
// It loads the native module object from the JSI or falls back to
// the bridge module (from NativeModulesProxy) if the remote debugger is on.
-export default requireNativeModule("CheckIosMarketplace");
+export default requireNativeModule(
+ "CheckIosMarketplace",
+) as CheckIosMarketplaceModule;
diff --git a/apps/expo/package.json b/apps/expo/package.json
index 3f86cfc..bf589dd 100644
--- a/apps/expo/package.json
+++ b/apps/expo/package.json
@@ -11,7 +11,7 @@
"android": "expo run:android",
"ios": "expo run:ios",
"apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease && mv app/build/outputs/apk/release/app-release.apk app/build/movie-web.apk",
- "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild clean archive -workspace movieweb.xcworkspace -scheme movieweb -configuration Release -destination generic/platform=iOS -archivePath build/movieweb.xcarchive CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_ALLOWED=NO | xcbeautify && cd build/movieweb.xcarchive/Products && mv Applications Payload && zip -r movie-web.ipa Payload && mv movie-web.ipa ../..",
+ "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild archive -workspace movieweb.xcworkspace -scheme movieweb -configuration Release -destination generic/platform=iOS -archivePath build/movieweb.xcarchive CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_ALLOWED=NO | xcbeautify && cd build/movieweb.xcarchive/Products && mv Applications Payload && zip -r movie-web.ipa Payload && mv movie-web.ipa ../..",
"ipa:sim": "expo prebuild --platform=ios && cd ios && xcodebuild clean archive -workspace movieweb.xcworkspace -scheme movieweb -configuration Release -destination \"generic/platform=iOS Simulator\" -archivePath build/movieweb.xcarchive CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_ALLOWED=NO | xcbeautify && cd build/movieweb.xcarchive/Products && mv Applications Payload && zip -r movie-web.ipa Payload && mv movie-web.ipa ../..",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint .",
diff --git a/apps/expo/src/app/(tabs)/downloads.tsx b/apps/expo/src/app/(tabs)/downloads.tsx
index cc0997b..4be65bc 100644
--- a/apps/expo/src/app/(tabs)/downloads.tsx
+++ b/apps/expo/src/app/(tabs)/downloads.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { Alert, Platform } from "react-native";
import { useFocusEffect, useRouter } from "expo-router";
import { MaterialCommunityIcons } from "@expo/vector-icons";
-import { isDevelopmentProvisioningProfile } from "modules/check-ios-certificate";
+import { getAppId, isIncorrectAppId } from "modules/check-ios-app-id";
import { ScrollView, useTheme, YStack } from "tamagui";
import type { ScrapeMedia } from "@movie-web/provider-utils";
@@ -81,10 +81,11 @@ const DownloadsScreen: React.FC = () => {
useFocusEffect(
React.useCallback(() => {
- if (Platform.OS === "ios" && !isDevelopmentProvisioningProfile()) {
+ if (Platform.OS === "ios" && isIncorrectAppId()) {
+ const appId = getAppId();
Alert.alert(
- "Production Certificate",
- "Download functionality is not available when the application is signed with a distribution certificate.",
+ "Wildcard/Mismatching App ID",
+ `The application is signed with a wildcard or mismatching App ID (${appId}). Download functionality is not available when the application is signed with a wildcard or mismatching App ID.`,
[
{
text: "OK",
@@ -148,14 +149,10 @@ const DownloadsScreen: React.FC = () => {
onPress={() => handlePress(download.downloads[0]!.localPath)}
/>
);
- } else {
- return (
-
- );
}
+ return (
+
+ );
})}
diff --git a/apps/expo/src/components/player/BottomControls.tsx b/apps/expo/src/components/player/BottomControls.tsx
index 76c8562..d7dc574 100644
--- a/apps/expo/src/components/player/BottomControls.tsx
+++ b/apps/expo/src/components/player/BottomControls.tsx
@@ -5,7 +5,7 @@ import Animated, {
useSharedValue,
withTiming,
} from "react-native-reanimated";
-import { isDevelopmentProvisioningProfile } from "modules/check-ios-certificate";
+import { isIncorrectAppId } from "modules/check-ios-app-id";
import { Text, View } from "tamagui";
import { LinearGradient } from "tamagui/linear-gradient";
@@ -39,12 +39,11 @@ export const BottomControls = () => {
(player.duration ?? 0) - (player.currentTime ?? 0),
)}`;
return { currentTime: current, remainingTime: remaining };
- } else {
- return {
- currentTime: mapSecondsToTime(0),
- remainingTime: mapSecondsToTime(0),
- };
}
+ return {
+ currentTime: mapSecondsToTime(0),
+ remainingTime: mapSecondsToTime(0),
+ };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [player?.currentTime]);
@@ -110,8 +109,7 @@ export const BottomControls = () => {
{Platform.OS === "android" ||
- (Platform.OS === "ios" &&
- isDevelopmentProvisioningProfile()) ? (
+ (Platform.OS === "ios" && !isIncorrectAppId()) ? (
) : null}
>