Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ const APP_VARIANT = resolveAppVariant(repoEnv.APP_VARIANT);
const isIosPersonalTeamBuild = repoEnv.T3CODE_IOS_PERSONAL_TEAM === "1";

const personalTeamBundleIdentifier = repoEnv.T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID?.trim();
const IOS_BUNDLE_IDENTIFIER_PATTERN = /^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/;

if (isIosPersonalTeamBuild && !personalTeamBundleIdentifier) {
if (
isIosPersonalTeamBuild &&
(!personalTeamBundleIdentifier ||
!IOS_BUNDLE_IDENTIFIER_PATTERN.test(personalTeamBundleIdentifier))
) {
throw new Error(
"T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID is required when T3CODE_IOS_PERSONAL_TEAM=1.",
"T3CODE_IOS_PERSONAL_TEAM_BUNDLE_ID must be a reverse-DNS identifier such as com.example.t3code when T3CODE_IOS_PERSONAL_TEAM=1.",
);
}

Expand Down Expand Up @@ -151,6 +156,8 @@ const config: ExpoConfig = {
"expo-asset",
"expo-font",
"expo-secure-store",
// appleSignIn must be gated here: withoutIosPersonalTeamCapabilities.cjs runs before
// plugins earlier in this array, so it cannot strip the entitlement Clerk would add.
["@clerk/expo", { theme: "./clerk-theme.json", appleSignIn: !isIosPersonalTeamBuild }],
"expo-web-browser",
[
Expand Down Expand Up @@ -194,6 +201,7 @@ const config: ExpoConfig = {
],
extra: {
appVariant: APP_VARIANT,
iosPersonalTeamBuild: isIosPersonalTeamBuild,
relay: {
url: repoEnv.T3CODE_RELAY_URL ?? null,
},
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"react-native": "0.85.3",
"react-native-gesture-handler": "~2.31.1",
"react-native-image-viewing": "^0.2.2",
"react-native-keyboard-controller": "1.21.6",
"react-native-keyboard-controller": "1.21.7",
"react-native-nitro-markdown": "^0.5.0",
"react-native-nitro-modules": "0.35.9",
"react-native-reanimated": "4.3.1",
Expand Down
5 changes: 5 additions & 0 deletions apps/mobile/src/features/agent-awareness/capabilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Constants from "expo-constants";

export function supportsAgentAwarenessPush() {
return Constants.expoConfig?.extra?.iosPersonalTeamBuild !== true;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { RelayDeviceRegistrationRequest } from "@t3tools/contracts/relay";

import type { Preferences } from "../../lib/storage";
import { supportsAgentAwarenessPush } from "./capabilities";

export function makeRelayDeviceRegistrationRequest(input: {
readonly deviceId: string;
Expand All @@ -12,7 +13,8 @@ export function makeRelayDeviceRegistrationRequest(input: {
readonly notificationsEnabled: boolean;
readonly preferences: Preferences;
}): RelayDeviceRegistrationRequest {
const liveActivitiesEnabled = input.preferences.liveActivitiesEnabled !== false;
const pushAvailable = supportsAgentAwarenessPush();
const liveActivitiesEnabled = pushAvailable && input.preferences.liveActivitiesEnabled !== false;
return {
deviceId: input.deviceId,
label: input.label,
Expand All @@ -23,7 +25,7 @@ export function makeRelayDeviceRegistrationRequest(input: {
...(input.pushToStartToken ? { pushToStartToken: input.pushToStartToken } : {}),
preferences: {
liveActivitiesEnabled,
notificationsEnabled: input.notificationsEnabled,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal Team tokens still sent

Medium Severity

For iOS Personal Team builds, makeRelayDeviceRegistrationRequest now forces preferences.notificationsEnabled and preferences.liveActivitiesEnabled off via supportsAgentAwarenessPush, but it still spreads pushToken and pushToStartToken from the caller when present. Relay can receive push tokens while preferences claim delivery is disabled, undermining the Personal Team hardening this PR adds elsewhere.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7be02cf. Configure here.

notificationsEnabled: pushAvailable && input.notificationsEnabled,
notifyOnApproval: true,
notifyOnInput: true,
notifyOnCompletion: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,26 @@ describe("makeRelayDeviceRegistrationRequest", () => {
});
});

it("disables push features in Personal Team relay registrations", () => {
Constants.expoConfig!.extra = { iosPersonalTeamBuild: true };

expect(
makeRelayDeviceRegistrationRequest({
deviceId: "device-1",
label: "Julius's iPhone",
iosMajorVersion: 18,
appVersion: "1.0.0",
pushToken: "apns-token",
pushToStartToken: "push-to-start-token",
notificationsEnabled: true,
preferences: {},
}).preferences,
).toMatchObject({
liveActivitiesEnabled: false,
notificationsEnabled: false,
});
});

it("marks notification delivery disabled when APNs permission is unavailable", () => {
expect(
makeRelayDeviceRegistrationRequest({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from "../../lib/storage";
import AgentActivity, { type AgentActivityProps } from "../../widgets/AgentActivity";
import { resolveCloudPublicConfig } from "../cloud/publicConfig";
import { supportsAgentAwarenessPush } from "./capabilities";
import { makeRelayDeviceRegistrationRequest } from "./registrationPayload";

const REMOTE_ACTIVITY_REGISTRATION_RETRY_MS = 15_000;
Expand Down Expand Up @@ -157,7 +158,7 @@ function iosMajorVersion(): number {

function nativePushTokenRegistration(observedPushToken?: string) {
return Effect.gen(function* () {
if (!canRegisterRemoteLiveActivities()) {
if (!canRegisterRemoteLiveActivities() || !supportsAgentAwarenessPush()) {
return { notificationsEnabled: false, pushToken: null };
}
if (observedPushToken) {
Expand Down
20 changes: 16 additions & 4 deletions apps/mobile/src/features/settings/SettingsRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
squashAtomCommandFailure,
} from "@t3tools/client-runtime/state/runtime";
import { AppText as Text } from "../../components/AppText";
import { supportsAgentAwarenessPush } from "../agent-awareness/capabilities";
import { setLiveActivityUpdatesEnabled } from "../agent-awareness/liveActivityPreferences";
import { requestAgentNotificationPermission } from "../agent-awareness/notificationPermissions";
import { refreshAgentAwarenessRegistration } from "../agent-awareness/remoteRegistration";
Expand Down Expand Up @@ -103,6 +104,7 @@ function LocalSettingsRouteScreen() {
}

function ConfiguredSettingsRouteScreen() {
const agentAwarenessPushAvailable = supportsAgentAwarenessPush();
const insets = useSafeAreaInsets();
const navigation = useNavigation();
const { expand: expandClerkSheet } = useClerkSettingsSheetDetent();
Expand Down Expand Up @@ -392,17 +394,27 @@ function ConfiguredSettingsRouteScreen() {
<SettingsSwitchRow
icon="bell.badge"
label="Device Notifications"
disabled={notificationStatus === "checking" || notificationStatus === "unsupported"}
value={notificationStatus === "enabled"}
disabled={
!agentAwarenessPushAvailable ||
notificationStatus === "checking" ||
notificationStatus === "unsupported"
}
value={agentAwarenessPushAvailable && notificationStatus === "enabled"}
onValueChange={handleDeviceNotificationsChange}
/>
<SettingsSwitchRow
disabled={
!isLoaded || liveActivityStatus === "checking" || liveActivityStatus === "linking"
!agentAwarenessPushAvailable ||
!isLoaded ||
liveActivityStatus === "checking" ||
liveActivityStatus === "linking"
}
icon="bolt.circle"
label="Live Activity Updates"
value={liveActivityStatus === "enabled" || liveActivityStatus === "linking"}
value={
agentAwarenessPushAvailable &&
(liveActivityStatus === "enabled" || liveActivityStatus === "linking")
}
onValueChange={handleLiveActivitiesChange}
/>
</SettingsSection>
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading