@oxy.so/services 9.2.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/AndroidManifest.xml +6 -6
  3. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionModule.kt +106 -41
  4. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionProvider.kt +45 -32
  5. package/android/src/main/java/so/oxy/devicesession/OxyDeviceSessionStore.kt +22 -27
  6. package/android/src/main/java/so/oxy/identity/OxyIdentityModule.kt +89 -43
  7. package/android/src/main/java/so/oxy/security/OxyCallerPolicy.kt +97 -0
  8. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionStore.kt +4 -10
  9. package/android/src/main/java/so/oxy/storage/OxyEncryptedPrefs.kt +17 -18
  10. package/ios/OxyIdentityModule.swift +13 -14
  11. package/lib/commonjs/ui/boot/runProviderColdBoot.js +2 -2
  12. package/lib/commonjs/ui/components/BenefitList.js +1 -1
  13. package/lib/commonjs/ui/components/BenefitList.js.map +1 -1
  14. package/lib/commonjs/ui/components/FollowButton.js +2 -2
  15. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/FollowTargetButton.js +2 -2
  17. package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
  18. package/lib/commonjs/ui/components/PeableButton.js +1 -2
  19. package/lib/commonjs/ui/components/PeableButton.js.map +1 -1
  20. package/lib/commonjs/ui/components/SurfaceHeaderAction.js +1 -1
  21. package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -1
  22. package/lib/commonjs/ui/components/SurfaceScreen.js +1 -1
  23. package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
  24. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +1 -1
  25. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  26. package/lib/commonjs/ui/components/authChooser/primitives.js +1 -1
  27. package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
  28. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js +1 -1
  29. package/lib/commonjs/ui/components/authChooser/requestSurfaces.js.map +1 -1
  30. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
  31. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  32. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js +2 -2
  33. package/lib/commonjs/ui/components/payment/PaymentMethodStep.js.map +1 -1
  34. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js +2 -2
  35. package/lib/commonjs/ui/components/payment/PaymentReviewStep.js.map +1 -1
  36. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js +1 -1
  37. package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  38. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +2 -2
  39. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  40. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +1 -1
  41. package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  42. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
  43. package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  44. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js +2 -2
  45. package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  46. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +2 -1
  47. package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
  48. package/lib/commonjs/ui/screens/AccountMembersScreen.js +4 -4
  49. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  50. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +1 -1
  51. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  52. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +1 -1
  53. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  54. package/lib/commonjs/ui/screens/DomainsScreen.js +1 -1
  55. package/lib/commonjs/ui/screens/DomainsScreen.js.map +1 -1
  56. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +4 -2
  57. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/FileManagementScreen.js +5 -5
  59. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  60. package/lib/commonjs/ui/screens/HistoryViewScreen.js +1 -1
  61. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  62. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +1 -1
  63. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  64. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +1 -1
  65. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  66. package/lib/commonjs/ui/screens/NotificationsScreen.js +8 -8
  67. package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
  68. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
  69. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  70. package/lib/commonjs/ui/screens/PreferencesScreen.js +2 -2
  71. package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
  72. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +37 -37
  73. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  74. package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
  75. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  76. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +5 -5
  77. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
  78. package/lib/commonjs/ui/screens/UserListScreen.js +1 -1
  79. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  80. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +11 -11
  81. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  82. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +1 -1
  83. package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
  84. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +1 -1
  85. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +1 -1
  87. package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  88. package/lib/commonjs/ui/session/tokenLossRecovery.js +1 -1
  89. package/lib/module/ui/boot/runProviderColdBoot.js +2 -2
  90. package/lib/module/ui/components/BenefitList.js +1 -1
  91. package/lib/module/ui/components/BenefitList.js.map +1 -1
  92. package/lib/module/ui/components/FollowButton.js +2 -2
  93. package/lib/module/ui/components/FollowButton.js.map +1 -1
  94. package/lib/module/ui/components/FollowTargetButton.js +2 -2
  95. package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
  96. package/lib/module/ui/components/PeableButton.js +2 -3
  97. package/lib/module/ui/components/PeableButton.js.map +1 -1
  98. package/lib/module/ui/components/SurfaceHeaderAction.js +1 -1
  99. package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -1
  100. package/lib/module/ui/components/SurfaceScreen.js +1 -1
  101. package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
  102. package/lib/module/ui/components/authChooser/AccountsMenuView.js +1 -1
  103. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  104. package/lib/module/ui/components/authChooser/primitives.js +1 -1
  105. package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
  106. package/lib/module/ui/components/authChooser/requestSurfaces.js +1 -1
  107. package/lib/module/ui/components/authChooser/requestSurfaces.js.map +1 -1
  108. package/lib/module/ui/components/payment/PaymentDetailsStep.js +2 -2
  109. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  110. package/lib/module/ui/components/payment/PaymentMethodStep.js +2 -2
  111. package/lib/module/ui/components/payment/PaymentMethodStep.js.map +1 -1
  112. package/lib/module/ui/components/payment/PaymentReviewStep.js +2 -2
  113. package/lib/module/ui/components/payment/PaymentReviewStep.js.map +1 -1
  114. package/lib/module/ui/components/payment/PaymentSuccessStep.js +1 -1
  115. package/lib/module/ui/components/payment/PaymentSuccessStep.js.map +1 -1
  116. package/lib/module/ui/components/payment/PaymentSummaryStep.js +2 -2
  117. package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  118. package/lib/module/ui/components/signIn/OxyAuthScreen.js +1 -1
  119. package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -1
  120. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
  121. package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
  122. package/lib/module/ui/components/signIn/OxyPasswordPanel.js +2 -2
  123. package/lib/module/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
  124. package/lib/module/ui/components/surfaces/ActionSheetSurface.js +2 -1
  125. package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
  126. package/lib/module/ui/screens/AccountMembersScreen.js +4 -4
  127. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  128. package/lib/module/ui/screens/AccountVerificationScreen.js +1 -1
  129. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  130. package/lib/module/ui/screens/ConnectedAppsScreen.js +1 -1
  131. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  132. package/lib/module/ui/screens/DomainsScreen.js +1 -1
  133. package/lib/module/ui/screens/DomainsScreen.js.map +1 -1
  134. package/lib/module/ui/screens/EditProfileFieldScreen.js +4 -2
  135. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  136. package/lib/module/ui/screens/FileManagementScreen.js +5 -5
  137. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  138. package/lib/module/ui/screens/HistoryViewScreen.js +1 -1
  139. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  140. package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
  141. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  142. package/lib/module/ui/screens/LegalDocumentsScreen.js +1 -1
  143. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  144. package/lib/module/ui/screens/NotificationsScreen.js +8 -8
  145. package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
  146. package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
  147. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  148. package/lib/module/ui/screens/PreferencesScreen.js +2 -2
  149. package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
  150. package/lib/module/ui/screens/PrivacySettingsScreen.js +37 -37
  151. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  152. package/lib/module/ui/screens/ProfileScreen.js +1 -1
  153. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  154. package/lib/module/ui/screens/SearchSettingsScreen.js +5 -5
  155. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
  156. package/lib/module/ui/screens/UserListScreen.js +1 -1
  157. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  158. package/lib/module/ui/screens/WelcomeNewUserScreen.js +11 -11
  159. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  160. package/lib/module/ui/screens/fileManagement/UploadBar.js +1 -1
  161. package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
  162. package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
  163. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  164. package/lib/module/ui/screens/trust/TrustRulesScreen.js +1 -1
  165. package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
  166. package/lib/module/ui/session/tokenLossRecovery.js +1 -1
  167. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts +2 -2
  168. package/lib/typescript/commonjs/ui/components/BenefitList.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +1 -1
  170. package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts +1 -1
  172. package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ui/components/PeableButton.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  176. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts +2 -2
  177. package/lib/typescript/module/ui/components/BenefitList.d.ts.map +1 -1
  178. package/lib/typescript/module/ui/components/FollowButton.d.ts +1 -1
  179. package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
  180. package/lib/typescript/module/ui/components/FollowTargetButton.d.ts +1 -1
  181. package/lib/typescript/module/ui/components/FollowTargetButton.d.ts.map +1 -1
  182. package/lib/typescript/module/ui/components/PeableButton.d.ts.map +1 -1
  183. package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
  184. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  185. package/package.json +7 -7
  186. package/plugins/withOxySharedPermissions.js +89 -0
  187. package/plugins/withSharedDeviceSessionProvider.js +26 -71
  188. package/src/ui/boot/runProviderColdBoot.ts +2 -2
  189. package/src/ui/components/BenefitList.tsx +1 -2
  190. package/src/ui/components/FollowButton.tsx +3 -3
  191. package/src/ui/components/FollowTargetButton.tsx +3 -3
  192. package/src/ui/components/PeableButton.tsx +3 -4
  193. package/src/ui/components/SurfaceHeaderAction.tsx +1 -1
  194. package/src/ui/components/SurfaceScreen.tsx +1 -1
  195. package/src/ui/components/__tests__/followButtonAccessibility.test.tsx +9 -0
  196. package/src/ui/components/authChooser/AccountsMenuView.tsx +1 -1
  197. package/src/ui/components/authChooser/primitives.tsx +1 -1
  198. package/src/ui/components/authChooser/requestSurfaces.tsx +1 -1
  199. package/src/ui/components/payment/PaymentDetailsStep.tsx +2 -2
  200. package/src/ui/components/payment/PaymentMethodStep.tsx +2 -2
  201. package/src/ui/components/payment/PaymentReviewStep.tsx +2 -2
  202. package/src/ui/components/payment/PaymentSuccessStep.tsx +1 -1
  203. package/src/ui/components/payment/PaymentSummaryStep.tsx +2 -2
  204. package/src/ui/components/signIn/OxyAuthScreen.tsx +1 -1
  205. package/src/ui/components/signIn/OxyLinkCommonsPanel.tsx +1 -1
  206. package/src/ui/components/signIn/OxyPasswordPanel.tsx +1 -1
  207. package/src/ui/components/surfaces/ActionSheetSurface.tsx +2 -1
  208. package/src/ui/screens/AccountMembersScreen.tsx +4 -4
  209. package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
  210. package/src/ui/screens/ConnectedAppsScreen.tsx +1 -1
  211. package/src/ui/screens/DomainsScreen.tsx +1 -1
  212. package/src/ui/screens/EditProfileFieldScreen.tsx +1 -2
  213. package/src/ui/screens/FileManagementScreen.tsx +5 -5
  214. package/src/ui/screens/HistoryViewScreen.tsx +1 -1
  215. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
  216. package/src/ui/screens/LegalDocumentsScreen.tsx +1 -1
  217. package/src/ui/screens/NotificationsScreen.tsx +8 -8
  218. package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
  219. package/src/ui/screens/PreferencesScreen.tsx +2 -2
  220. package/src/ui/screens/PrivacySettingsScreen.tsx +21 -21
  221. package/src/ui/screens/ProfileScreen.tsx +1 -1
  222. package/src/ui/screens/SearchSettingsScreen.tsx +5 -5
  223. package/src/ui/screens/UserListScreen.tsx +1 -1
  224. package/src/ui/screens/WelcomeNewUserScreen.tsx +11 -11
  225. package/src/ui/screens/fileManagement/UploadBar.tsx +1 -1
  226. package/src/ui/screens/trust/TrustCenterScreen.tsx +1 -1
  227. package/src/ui/screens/trust/TrustRulesScreen.tsx +1 -1
  228. package/src/ui/session/__tests__/tokenLossRecovery.test.ts +2 -2
  229. package/src/ui/session/tokenLossRecovery.ts +1 -1
  230. package/android/src/main/java/so/oxy/identity/OxyIdentityProvider.kt +0 -77
  231. package/android/src/main/java/so/oxy/identity/OxyIdentityStore.kt +0 -66
  232. package/plugins/withSharedDeviceSessionReader.js +0 -57
  233. package/plugins/withSharedIdentityProvider.js +0 -83
  234. package/plugins/withSharedIdentityReader.js +0 -46
@@ -109,7 +109,7 @@ const HistoryViewScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) => {
109
109
  />
110
110
  </SettingsListGroup>
111
111
  <SettingsListGroup title={t('history.recent') || 'Recent History'}>
112
- {isLoading ? <Loading size="large" color={bloomTheme.colors.text} text={t('history.loading') || 'Loading history...'} />
112
+ {isLoading ? <Loading size="lg" color={bloomTheme.colors.text} text={t('history.loading') || 'Loading history...'} />
113
113
  : history.length === 0 ? <Text className="text-text-secondary text-center p-space-40">{t('history.empty') || 'No history yet'}</Text>
114
114
  : history.map(item => (
115
115
  <SettingsListItem
@@ -197,7 +197,7 @@ const LanguageSelectorScreen: React.FC<LanguageSelectorScreenProps> = () => {
197
197
  </Text>
198
198
  </View>
199
199
  ) : canRemove ? (
200
- <Button appearance="plain" tone="neutral" size="small" iconOnly stopPropagation
200
+ <Button appearance="plain" tone="neutral" size="sm" iconOnly stopPropagation
201
201
  onPress={() => handleRemove(entry.code)} disabled={isBusy}
202
202
  accessibilityLabel={`${t('language.remove')} ${entry.name}`}
203
203
  icon={<Ionicons name="close-circle" size={REMOVE_ICON_SIZE} color={bloomTheme.colors.textSecondary} />} />
@@ -112,7 +112,7 @@ const LegalDocumentsScreen: React.FC<BaseScreenProps> = ({
112
112
  if (documentType) {
113
113
  return (
114
114
  <Loading
115
- size="large"
115
+ size="lg"
116
116
  color={bloomTheme.colors.text}
117
117
  text={t('legal.opening') || 'Opening document...'}
118
118
  />
@@ -90,8 +90,8 @@ const NotificationsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
90
90
  }
91
91
  rightElement={
92
92
  <Switch
93
- value={values.pushEnabled}
94
- onValueChange={() => toggle('pushEnabled')}
93
+ checked={values.pushEnabled}
94
+ onCheckedChange={() => toggle('pushEnabled')}
95
95
  disabled={isSaving}
96
96
  />
97
97
  }
@@ -111,8 +111,8 @@ const NotificationsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
111
111
  }
112
112
  rightElement={
113
113
  <Switch
114
- value={values.emailDigest}
115
- onValueChange={() => toggle('emailDigest')}
114
+ checked={values.emailDigest}
115
+ onCheckedChange={() => toggle('emailDigest')}
116
116
  disabled={isSaving}
117
117
  />
118
118
  }
@@ -139,8 +139,8 @@ const NotificationsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
139
139
  }
140
140
  rightElement={
141
141
  <Switch
142
- value={values.securityAlerts}
143
- onValueChange={() => toggle('securityAlerts')}
142
+ checked={values.securityAlerts}
143
+ onCheckedChange={() => toggle('securityAlerts')}
144
144
  disabled={isSaving}
145
145
  />
146
146
  }
@@ -168,8 +168,8 @@ const NotificationsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
168
168
  }
169
169
  rightElement={
170
170
  <Switch
171
- value={values.marketingEmails}
172
- onValueChange={() => toggle('marketingEmails')}
171
+ checked={values.marketingEmails}
172
+ onCheckedChange={() => toggle('marketingEmails')}
173
173
  disabled={isSaving}
174
174
  />
175
175
  }
@@ -197,7 +197,7 @@ const PaymentGatewayScreen: React.FC<PaymentGatewayScreenProps> = (props) => {
197
197
  <Button
198
198
  appearance="solid" tone="accent"
199
199
  onPress={handleClose}
200
- size="small"
200
+ size="sm"
201
201
  icon={<Ionicons name="close" size={16} />}
202
202
  iconPosition="right"
203
203
  >
@@ -158,8 +158,8 @@ const PreferencesScreen: React.FC<BaseScreenProps> = ({
158
158
  }
159
159
  rightElement={
160
160
  <Switch
161
- value={reduceMotionPref}
162
- onValueChange={handleReduceMotionToggle}
161
+ checked={reduceMotionPref}
162
+ onCheckedChange={handleReduceMotionToggle}
163
163
  disabled={isSaving}
164
164
  />
165
165
  }
@@ -192,7 +192,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
192
192
  if (isLoading) {
193
193
  return (
194
194
  <>
195
- <Loading size="large" color={bloomTheme.colors.text} />
195
+ <Loading size="lg" color={bloomTheme.colors.text} />
196
196
  </>
197
197
  );
198
198
  }
@@ -207,28 +207,28 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
207
207
  icon={<SettingsIcon name="lock-outline" color={bloomTheme.colors.primary} />}
208
208
  title={t('privacySettings.isPrivateAccount') || 'Private Account'}
209
209
  description={t('privacySettings.isPrivateAccountDesc') || 'Only approved followers can see your posts'}
210
- rightElement={<Switch value={settings.isPrivateAccount} onValueChange={() => toggle('isPrivateAccount')} disabled={isSaving} />}
210
+ rightElement={<Switch checked={settings.isPrivateAccount} onCheckedChange={() => toggle('isPrivateAccount')} disabled={isSaving} />}
211
211
  showChevron={false}
212
212
  />
213
213
  <SettingsListItem
214
214
  icon={<SettingsIcon name="account-eye-outline" color={bloomTheme.colors.info} />}
215
215
  title={t('privacySettings.profileVisibility') || 'Profile Visibility'}
216
216
  description={t('privacySettings.profileVisibilityDesc') || 'Control who can view your profile'}
217
- rightElement={<Switch value={settings.profileVisibility} onValueChange={() => toggle('profileVisibility')} disabled={isSaving} />}
217
+ rightElement={<Switch checked={settings.profileVisibility} onCheckedChange={() => toggle('profileVisibility')} disabled={isSaving} />}
218
218
  showChevron={false}
219
219
  />
220
220
  <SettingsListItem
221
221
  icon={<SettingsIcon name="circle-outline" color={bloomTheme.colors.success} />}
222
222
  title={t('privacySettings.hideOnlineStatus') || 'Hide Online Status'}
223
223
  description={t('privacySettings.hideOnlineStatusDesc') || 'Don\'t show when you\'re online'}
224
- rightElement={<Switch value={settings.hideOnlineStatus} onValueChange={() => toggle('hideOnlineStatus')} disabled={isSaving} />}
224
+ rightElement={<Switch checked={settings.hideOnlineStatus} onCheckedChange={() => toggle('hideOnlineStatus')} disabled={isSaving} />}
225
225
  showChevron={false}
226
226
  />
227
227
  <SettingsListItem
228
228
  icon={<SettingsIcon name="clock-outline" color={bloomTheme.colors.secondary} />}
229
229
  title={t('privacySettings.hideLastSeen') || 'Hide Last Seen'}
230
230
  description={t('privacySettings.hideLastSeenDesc') || 'Don\'t show when you were last active'}
231
- rightElement={<Switch value={settings.hideLastSeen} onValueChange={() => toggle('hideLastSeen')} disabled={isSaving} />}
231
+ rightElement={<Switch checked={settings.hideLastSeen} onCheckedChange={() => toggle('hideLastSeen')} disabled={isSaving} />}
232
232
  showChevron={false}
233
233
  />
234
234
  </SettingsListGroup>
@@ -239,28 +239,28 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
239
239
  icon={<SettingsIcon name="tag-outline" color={bloomTheme.colors.primary} />}
240
240
  title={t('privacySettings.allowTagging') || 'Allow Tagging'}
241
241
  description={t('privacySettings.allowTaggingDesc') || 'Let others tag you in posts'}
242
- rightElement={<Switch value={settings.allowTagging} onValueChange={() => toggle('allowTagging')} disabled={isSaving} />}
242
+ rightElement={<Switch checked={settings.allowTagging} onCheckedChange={() => toggle('allowTagging')} disabled={isSaving} />}
243
243
  showChevron={false}
244
244
  />
245
245
  <SettingsListItem
246
246
  icon={<SettingsIcon name="at" color={bloomTheme.colors.info} />}
247
247
  title={t('privacySettings.allowMentions') || 'Allow Mentions'}
248
248
  description={t('privacySettings.allowMentionsDesc') || 'Let others mention you'}
249
- rightElement={<Switch value={settings.allowMentions} onValueChange={() => toggle('allowMentions')} disabled={isSaving} />}
249
+ rightElement={<Switch checked={settings.allowMentions} onCheckedChange={() => toggle('allowMentions')} disabled={isSaving} />}
250
250
  showChevron={false}
251
251
  />
252
252
  <SettingsListItem
253
253
  icon={<SettingsIcon name="message-outline" color={bloomTheme.colors.success} />}
254
254
  title={t('privacySettings.allowDirectMessages') || 'Allow Direct Messages'}
255
255
  description={t('privacySettings.allowDirectMessagesDesc') || 'Let others send you direct messages'}
256
- rightElement={<Switch value={settings.allowDirectMessages} onValueChange={() => toggle('allowDirectMessages')} disabled={isSaving} />}
256
+ rightElement={<Switch checked={settings.allowDirectMessages} onCheckedChange={() => toggle('allowDirectMessages')} disabled={isSaving} />}
257
257
  showChevron={false}
258
258
  />
259
259
  <SettingsListItem
260
260
  icon={<SettingsIcon name="check-all" color={bloomTheme.colors.secondary} />}
261
261
  title={t('privacySettings.hideReadReceipts') || 'Hide Read Receipts'}
262
262
  description={t('privacySettings.hideReadReceiptsDesc') || 'Don\'t show read receipts in messages'}
263
- rightElement={<Switch value={settings.hideReadReceipts} onValueChange={() => toggle('hideReadReceipts')} disabled={isSaving} />}
263
+ rightElement={<Switch checked={settings.hideReadReceipts} onCheckedChange={() => toggle('hideReadReceipts')} disabled={isSaving} />}
264
264
  showChevron={false}
265
265
  />
266
266
  </SettingsListGroup>
@@ -271,28 +271,28 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
271
271
  icon={<SettingsIcon name="pulse" color={bloomTheme.colors.primary} />}
272
272
  title={t('privacySettings.showActivity') || 'Show Activity Status'}
273
273
  description={t('privacySettings.showActivityDesc') || 'Display your activity on your profile'}
274
- rightElement={<Switch value={settings.showActivity} onValueChange={() => toggle('showActivity')} disabled={isSaving} />}
274
+ rightElement={<Switch checked={settings.showActivity} onCheckedChange={() => toggle('showActivity')} disabled={isSaving} />}
275
275
  showChevron={false}
276
276
  />
277
277
  <SettingsListItem
278
278
  icon={<SettingsIcon name="database-outline" color={bloomTheme.colors.info} />}
279
279
  title={t('privacySettings.dataSharing') || 'Data Sharing'}
280
280
  description={t('privacySettings.dataSharingDesc') || 'Allow sharing data for personalization'}
281
- rightElement={<Switch value={settings.dataSharing} onValueChange={() => toggle('dataSharing')} disabled={isSaving} />}
281
+ rightElement={<Switch checked={settings.dataSharing} onCheckedChange={() => toggle('dataSharing')} disabled={isSaving} />}
282
282
  showChevron={false}
283
283
  />
284
284
  <SettingsListItem
285
285
  icon={<SettingsIcon name="map-marker-outline" color={bloomTheme.colors.warning} />}
286
286
  title={t('privacySettings.locationSharing') || 'Location Sharing'}
287
287
  description={t('privacySettings.locationSharingDesc') || 'Share your location'}
288
- rightElement={<Switch value={settings.locationSharing} onValueChange={() => toggle('locationSharing')} disabled={isSaving} />}
288
+ rightElement={<Switch checked={settings.locationSharing} onCheckedChange={() => toggle('locationSharing')} disabled={isSaving} />}
289
289
  showChevron={false}
290
290
  />
291
291
  <SettingsListItem
292
292
  icon={<SettingsIcon name="chart-line" color={bloomTheme.colors.secondary} />}
293
293
  title={t('privacySettings.analyticsSharing') || 'Analytics Sharing'}
294
294
  description={t('privacySettings.analyticsSharingDesc') || 'Allow analytics data collection'}
295
- rightElement={<Switch value={settings.analyticsSharing} onValueChange={() => toggle('analyticsSharing')} disabled={isSaving} />}
295
+ rightElement={<Switch checked={settings.analyticsSharing} onCheckedChange={() => toggle('analyticsSharing')} disabled={isSaving} />}
296
296
  showChevron={false}
297
297
  />
298
298
  </SettingsListGroup>
@@ -303,28 +303,28 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
303
303
  icon={<SettingsIcon name="eye-off-outline" color={bloomTheme.colors.warning} />}
304
304
  title={t('privacySettings.sensitiveContent') || 'Show Sensitive Content'}
305
305
  description={t('privacySettings.sensitiveContentDesc') || 'Allow sensitive or explicit content'}
306
- rightElement={<Switch value={settings.sensitiveContent} onValueChange={() => toggle('sensitiveContent')} disabled={isSaving} />}
306
+ rightElement={<Switch checked={settings.sensitiveContent} onCheckedChange={() => toggle('sensitiveContent')} disabled={isSaving} />}
307
307
  showChevron={false}
308
308
  />
309
309
  <SettingsListItem
310
310
  icon={<SettingsIcon name="filter-outline" color={bloomTheme.colors.success} />}
311
311
  title={t('privacySettings.autoFilter') || 'Auto Filter'}
312
312
  description={t('privacySettings.autoFilterDesc') || 'Automatically filter inappropriate content'}
313
- rightElement={<Switch value={settings.autoFilter} onValueChange={() => toggle('autoFilter')} disabled={isSaving} />}
313
+ rightElement={<Switch checked={settings.autoFilter} onCheckedChange={() => toggle('autoFilter')} disabled={isSaving} />}
314
314
  showChevron={false}
315
315
  />
316
316
  <SettingsListItem
317
317
  icon={<SettingsIcon name="volume-off" color={bloomTheme.colors.info} />}
318
318
  title={t('privacySettings.muteKeywords') || 'Mute Keywords'}
319
319
  description={t('privacySettings.muteKeywordsDesc') || 'Hide posts containing muted keywords'}
320
- rightElement={<Switch value={settings.muteKeywords} onValueChange={() => toggle('muteKeywords')} disabled={isSaving} />}
320
+ rightElement={<Switch checked={settings.muteKeywords} onCheckedChange={() => toggle('muteKeywords')} disabled={isSaving} />}
321
321
  showChevron={false}
322
322
  />
323
323
  <SettingsListItem
324
324
  icon={<SettingsIcon name="cellphone-screenshot" color={bloomTheme.colors.secondary} />}
325
325
  title={t('privacySettings.blockScreenshots') || 'Block Screenshots'}
326
326
  description={t('privacySettings.blockScreenshotsDesc') || 'Prevent screenshots of your content'}
327
- rightElement={<Switch value={settings.blockScreenshots} onValueChange={() => toggle('blockScreenshots')} disabled={isSaving} />}
327
+ rightElement={<Switch checked={settings.blockScreenshots} onCheckedChange={() => toggle('blockScreenshots')} disabled={isSaving} />}
328
328
  showChevron={false}
329
329
  />
330
330
  </SettingsListGroup>
@@ -332,7 +332,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
332
332
  {/* Blocked Users */}
333
333
  <SettingsListGroup title={t('privacySettings.sections.blockedUsers') || 'BLOCKED USERS'}>
334
334
  {isLoadingUsers ? (
335
- <Loading size="small" color={bloomTheme.colors.text} />
335
+ <Loading size="sm" color={bloomTheme.colors.text} />
336
336
  ) : blockedUsers.length === 0 ? (
337
337
  <Text className="text-text-secondary text-center p-space-40">
338
338
  {t('privacySettings.noBlockedUsers') || 'No blocked users'}
@@ -349,7 +349,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
349
349
  rightElement={
350
350
  <Button
351
351
  appearance="solid" tone="danger"
352
- size="small"
352
+ size="sm"
353
353
  onPress={() => handleUnblock(userId)}
354
354
  >
355
355
  {t('privacySettings.unblock') || 'Unblock'}
@@ -365,7 +365,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
365
365
  {/* Restricted Users */}
366
366
  <SettingsListGroup title={t('privacySettings.sections.restrictedUsers') || 'RESTRICTED USERS'}>
367
367
  {isLoadingUsers ? (
368
- <Loading size="small" color={bloomTheme.colors.text} />
368
+ <Loading size="sm" color={bloomTheme.colors.text} />
369
369
  ) : restrictedUsers.length === 0 ? (
370
370
  <Text className="text-text-secondary text-center p-space-40">
371
371
  {t('privacySettings.noRestrictedUsers') || 'No restricted users'}
@@ -383,7 +383,7 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
383
383
  rightElement={
384
384
  <Button
385
385
  appearance="subtle" tone="neutral"
386
- size="small"
386
+ size="sm"
387
387
  onPress={() => handleUnrestrict(userId)}
388
388
  >
389
389
  {t('privacySettings.unrestrict') || 'Unrestrict'}
@@ -210,7 +210,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
210
210
  {isOwnProfile ? (
211
211
  <Button
212
212
  appearance="subtle" tone="neutral"
213
- size="small"
213
+ size="sm"
214
214
  onPress={() => navigate?.('ManageAccount')}
215
215
  >
216
216
  {t('editProfile.title') || 'Edit Profile'}
@@ -70,7 +70,7 @@ const SearchSettingsScreen: React.FC<BaseScreenProps> = ({
70
70
  if (isLoading) {
71
71
  return (
72
72
  <>
73
- <Loading size="large" color={bloomTheme.colors.text} />
73
+ <Loading size="lg" color={bloomTheme.colors.text} />
74
74
  </>
75
75
  );
76
76
  }
@@ -92,8 +92,8 @@ const SearchSettingsScreen: React.FC<BaseScreenProps> = ({
92
92
  description={t('searchSettings.safeSearch.description') || 'Filter out explicit content from search results'}
93
93
  rightElement={
94
94
  <Switch
95
- value={settings.safeSearch}
96
- onValueChange={() => toggle('safeSearch')}
95
+ checked={settings.safeSearch}
96
+ onCheckedChange={() => toggle('safeSearch')}
97
97
  disabled={isSaving}
98
98
  />
99
99
  }
@@ -114,8 +114,8 @@ const SearchSettingsScreen: React.FC<BaseScreenProps> = ({
114
114
  description={t('searchSettings.personalization.description') || 'Use your activity to improve search results'}
115
115
  rightElement={
116
116
  <Switch
117
- value={settings.searchPersonalization}
118
- onValueChange={() => toggle('searchPersonalization')}
117
+ checked={settings.searchPersonalization}
118
+ onCheckedChange={() => toggle('searchPersonalization')}
119
119
  disabled={isSaving}
120
120
  />
121
121
  }
@@ -172,7 +172,7 @@ const UserListScreen: React.FC<UserListScreenProps> = ({
172
172
  </Text> : null}
173
173
  {description ? <Text className="text-text-secondary text-sm mt-space-4" numberOfLines={2}>{description}</Text> : null}
174
174
  </View>} />
175
- {!isCurrentUser && itemUserId ? <FollowButton userId={itemUserId} size="small" /> : null}
175
+ {!isCurrentUser && itemUserId ? <FollowButton userId={itemUserId} size="sm" /> : null}
176
176
  </View>
177
177
  );
178
178
  },
@@ -182,10 +182,10 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
182
182
  if (currentStep === totalSteps - 1) {
183
183
  return (
184
184
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
185
- <Button appearance="subtle" tone="neutral" onPress={prevStep} size="small">
185
+ <Button appearance="subtle" tone="neutral" onPress={prevStep} size="sm">
186
186
  {t('welcomeNew.actions.back') || 'Back'}
187
187
  </Button>
188
- <Button appearance="solid" tone="accent" onPress={finish} size="small">
188
+ <Button appearance="solid" tone="accent" onPress={finish} size="sm">
189
189
  {t('welcomeNew.actions.enter') || 'Enter'}
190
190
  </Button>
191
191
  </View>
@@ -195,11 +195,11 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
195
195
  return (
196
196
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
197
197
  {avatarStepIndex > 0 && (
198
- <Button appearance="subtle" tone="neutral" onPress={skipToAvatar} size="small">
198
+ <Button appearance="subtle" tone="neutral" onPress={skipToAvatar} size="sm">
199
199
  {t('welcomeNew.actions.skip') || 'Skip'}
200
200
  </Button>
201
201
  )}
202
- <Button appearance="solid" tone="accent" onPress={nextStep} size="small">
202
+ <Button appearance="solid" tone="accent" onPress={nextStep} size="sm">
203
203
  {t('welcomeNew.actions.next') || 'Next'}
204
204
  </Button>
205
205
  </View>
@@ -208,10 +208,10 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
208
208
  if (nameStepIndex >= 0 && currentStep === nameStepIndex) {
209
209
  return (
210
210
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
211
- <Button appearance="subtle" tone="neutral" onPress={prevStep} size="small">
211
+ <Button appearance="subtle" tone="neutral" onPress={prevStep} size="sm">
212
212
  {t('welcomeNew.actions.back') || 'Back'}
213
213
  </Button>
214
- <Button appearance="solid" tone="accent" onPress={submitName} size="small" disabled={!firstName.trim() || savingName} loading={savingName}>
214
+ <Button appearance="solid" tone="accent" onPress={submitName} size="sm" disabled={!firstName.trim() || savingName} loading={savingName}>
215
215
  {t('welcomeNew.actions.continue') || 'Continue'}
216
216
  </Button>
217
217
  </View>
@@ -220,10 +220,10 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
220
220
  if (step.showAvatar) {
221
221
  return (
222
222
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
223
- <Button appearance="subtle" tone="neutral" onPress={prevStep} size="small">
223
+ <Button appearance="subtle" tone="neutral" onPress={prevStep} size="sm">
224
224
  {t('welcomeNew.actions.back') || 'Back'}
225
225
  </Button>
226
- <Button appearance="solid" tone="accent" onPress={nextStep} size="small">
226
+ <Button appearance="solid" tone="accent" onPress={nextStep} size="sm">
227
227
  {avatarUri ? (t('welcomeNew.actions.continue') || 'Continue') : (t('welcomeNew.actions.skip') || 'Skip')}
228
228
  </Button>
229
229
  </View>
@@ -231,10 +231,10 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
231
231
  }
232
232
  return (
233
233
  <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
234
- <Button appearance="subtle" tone="neutral" onPress={prevStep} size="small">
234
+ <Button appearance="subtle" tone="neutral" onPress={prevStep} size="sm">
235
235
  {t('welcomeNew.actions.back') || 'Back'}
236
236
  </Button>
237
- <Button appearance="solid" tone="accent" onPress={nextStep} size="small">
237
+ <Button appearance="solid" tone="accent" onPress={nextStep} size="sm">
238
238
  {t('welcomeNew.actions.next') || 'Next'}
239
239
  </Button>
240
240
  </View>
@@ -296,7 +296,7 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: User }> = ({
296
296
  placeholderColor={`${colors.primary}20`}
297
297
  style={styles.avatar}
298
298
  />
299
- <Button appearance="solid" tone="accent" size="small" onPress={openAvatarPicker}>
299
+ <Button appearance="solid" tone="accent" size="sm" onPress={openAvatarPicker}>
300
300
  {avatarUri ? (t('welcomeNew.avatar.change') || 'Change Avatar') : (t('welcomeNew.avatar.add') || 'Add Avatar')}
301
301
  </Button>
302
302
  </View>
@@ -23,7 +23,7 @@ const UploadBar: React.FC<UploadBarProps> = ({ uploadProgress, t }) => (
23
23
  accessibilityLabel={t('fileManagement.uploading')} />
24
24
  ) : null}
25
25
  </View>
26
- <Loading size="small" />
26
+ <Loading size="sm" />
27
27
  </Card>
28
28
  </View>
29
29
  );
@@ -70,7 +70,7 @@ const TrustCenterScreen: React.FC<BaseScreenProps> = ({
70
70
  if (isLoading) {
71
71
  return (
72
72
  <View className="items-center py-space-40">
73
- <Loading size="large" color={primaryColor} />
73
+ <Loading size="lg" color={primaryColor} />
74
74
  </View>
75
75
  );
76
76
  }
@@ -70,7 +70,7 @@ const TrustRulesScreen: React.FC<BaseScreenProps> = () => {
70
70
  return (
71
71
  <>
72
72
  {isLoading ? (
73
- <Loading size="large" color={bloomTheme.colors.primary} />
73
+ <Loading size="lg" color={bloomTheme.colors.primary} />
74
74
  ) : error ? (
75
75
  <Text className="text-text-secondary text-base text-center px-screen-margin pt-space-40">
76
76
  {error}
@@ -102,7 +102,7 @@ describe('token loss recovery', () => {
102
102
  });
103
103
 
104
104
  it('re-establishes through the shared identity when the credential is gone, like the cold boot does', async () => {
105
- const h = harness([null, 'from-shared-key']);
105
+ const h = harness([null, 'from-commons-proof']);
106
106
  h.state.credential = false;
107
107
  h.state.keyed = true;
108
108
  const recovery = createTokenLossRecovery(h.deps);
@@ -111,7 +111,7 @@ describe('token loss recovery', () => {
111
111
  await runToCompletion(recovery);
112
112
 
113
113
  expect(h.signOutLocally).not.toHaveBeenCalled();
114
- expect(h.state.token).toBe('from-shared-key');
114
+ expect(h.state.token).toBe('from-commons-proof');
115
115
  });
116
116
 
117
117
  it('gives the key-based lane a bounded number of tries, then signs out', async () => {
@@ -21,7 +21,7 @@
21
21
  * this loop in a sign-out — so a real revocation still signs out.
22
22
  * - No credential, but a key-based lane can still re-establish (the native
23
23
  * shared identity, or an identity-bound client's own key) → try that a few
24
- * times, as the cold boot's shared-key step would, then sign out.
24
+ * times, as the cold boot's Commons-proof step would, then sign out.
25
25
  * - Neither → the session is over. Sign out now, as before.
26
26
  *
27
27
  * Framework-free and clock-injectable so the policy is unit tested without a
@@ -1,77 +0,0 @@
1
- package so.oxy.identity
2
-
3
- import android.content.ContentProvider
4
- import android.content.ContentValues
5
- import android.content.Context
6
- import android.content.pm.PackageManager
7
- import android.database.Cursor
8
- import android.net.Uri
9
- import android.os.Bundle
10
-
11
- /**
12
- * Cross-process read surface for the shared Oxy identity, hosted ONLY by Commons
13
- * (declared per-app by the `withSharedIdentityProvider` config plugin with a
14
- * `signature`-level permission, authority `${applicationId}.identity`).
15
- *
16
- * `call("getShared")` returns the keypair from Commons's own
17
- * EncryptedSharedPreferences — but ONLY after verifying the caller is signed
18
- * with the SAME certificate. That signature check is belt-and-suspenders on top
19
- * of the manifest's `signature` permission: even if the permission gate were
20
- * ever misconfigured, a differently-signed caller still gets null.
21
- *
22
- * All standard CRUD operations are no-ops; this provider exists solely for the
23
- * `call()` channel.
24
- */
25
- class OxyIdentityProvider : ContentProvider() {
26
- override fun onCreate(): Boolean = true
27
-
28
- override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
29
- if (method != METHOD_GET_SHARED) return null
30
- val ctx = context ?: return null
31
- if (!callerSignatureMatches(ctx)) return null
32
-
33
- val pair = runCatching { OxyIdentityStore.read(ctx) }.getOrNull() ?: return null
34
- return Bundle().apply {
35
- putString(OxyIdentityStore.KEY_PRIVATE, pair.first)
36
- putString(OxyIdentityStore.KEY_PUBLIC, pair.second)
37
- }
38
- }
39
-
40
- /**
41
- * True when the calling package shares this app's signing certificate. Uses
42
- * `checkSignatures` (deprecated but still the simplest correct cross-package
43
- * signature comparison; returns SIGNATURE_MATCH only for same-cert apps).
44
- */
45
- private fun callerSignatureMatches(ctx: Context): Boolean {
46
- val caller = callingPackage ?: return false
47
- return runCatching {
48
- @Suppress("DEPRECATION")
49
- ctx.packageManager.checkSignatures(caller, ctx.packageName) == PackageManager.SIGNATURE_MATCH
50
- }.getOrDefault(false)
51
- }
52
-
53
- override fun query(
54
- uri: Uri,
55
- projection: Array<out String>?,
56
- selection: String?,
57
- selectionArgs: Array<out String>?,
58
- sortOrder: String?
59
- ): Cursor? = null
60
-
61
- override fun getType(uri: Uri): String? = null
62
-
63
- override fun insert(uri: Uri, values: ContentValues?): Uri? = null
64
-
65
- override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
66
-
67
- override fun update(
68
- uri: Uri,
69
- values: ContentValues?,
70
- selection: String?,
71
- selectionArgs: Array<out String>?
72
- ): Int = 0
73
-
74
- companion object {
75
- private const val METHOD_GET_SHARED = "getShared"
76
- }
77
- }
@@ -1,66 +0,0 @@
1
- package so.oxy.identity
2
-
3
- import android.content.Context
4
- import android.content.SharedPreferences
5
- import so.oxy.storage.OxyEncryptedPrefs
6
- import so.oxy.storage.RecoveryPolicy
7
-
8
- /**
9
- * Shared accessor for the hardware-backed EncryptedSharedPreferences that holds
10
- * the cross-app Oxy identity keypair.
11
- *
12
- * Used by BOTH [OxyIdentityModule] (the JS bridge / local read + write) and
13
- * [OxyIdentityProvider] (the cross-process read surface) so the store name and
14
- * the encryption scheme can never drift between the two halves.
15
- *
16
- * Opening the file — the single-memoized-instance rule and the two-stage keyset
17
- * self-heal, both load-bearing and non-obvious — lives in [OxyEncryptedPrefs],
18
- * which is shared with the background-session store. Read its documentation
19
- * before changing anything about how this file is opened.
20
- *
21
- * One consequence worth restating here: an open can legitimately return an EMPTY
22
- * file (the self-heal wipes a keyset it cannot read). That is safe for this slot
23
- * specifically because it is a DERIVED copy — Commons re-populates it from the
24
- * primary self-custody identity on the next boot (`migrateToSharedIdentity`), and
25
- * that primary lives in expo-secure-store under a different file and different
26
- * keystore aliases, untouched by any recovery here.
27
- */
28
- internal object OxyIdentityStore {
29
- const val PREFS_NAME = "oxy_shared_identity"
30
- const val KEY_PRIVATE = "priv"
31
- const val KEY_PUBLIC = "pub"
32
-
33
- /**
34
- * [RecoveryPolicy.RebuildFileOnly], like every other store (OxyHQ/oxy#1388).
35
- * This store used to regenerate the UID-shared androidx master key when its
36
- * keyset could not be rebuilt, which made every other Oxy app's encrypted prefs
37
- * unreadable. It never needs to: this slot is a DERIVED copy that Commons
38
- * re-populates from the primary identity on every launch
39
- * (`KeyManager.syncSharedIdentity`), so an empty or unavailable slot costs
40
- * nothing that a relaunch of Commons does not restore.
41
- */
42
- private fun prefs(context: Context): SharedPreferences =
43
- OxyEncryptedPrefs.open(context, PREFS_NAME, RecoveryPolicy.RebuildFileOnly)
44
-
45
- /** Read the stored keypair as (privateKey, publicKey), or null when absent/blank. */
46
- fun read(context: Context): Pair<String, String>? {
47
- val p = prefs(context)
48
- val priv = p.getString(KEY_PRIVATE, null) ?: return null
49
- val pub = p.getString(KEY_PUBLIC, null) ?: return null
50
- if (priv.isEmpty() || pub.isEmpty()) return null
51
- return priv to pub
52
- }
53
-
54
- fun write(context: Context, priv: String, pub: String) {
55
- // commit() (synchronous) so a cross-process reader that fires immediately
56
- // after the write is guaranteed to see the flushed value.
57
- prefs(context).edit()
58
- .putString(KEY_PRIVATE, priv)
59
- .putString(KEY_PUBLIC, pub)
60
- .commit()
61
- }
62
-
63
- fun clear(context: Context) {
64
- prefs(context).edit().clear().commit()
65
- }
66
- }