@ethora/chat-component-rn 26.8.1 → 26.8.2

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 (604) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +43 -10
  3. package/lib/commonjs/assets/icons.js +7 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/AuthForms/Login.js +4 -4
  6. package/lib/commonjs/components/AuthForms/Login.js.map +1 -1
  7. package/lib/commonjs/components/Header/HeaderRoomList.js +29 -8
  8. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ChatHeader.js +9 -3
  10. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/ChatRoom.js +150 -14
  12. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/ChatWrapper.js +34 -13
  14. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  15. package/lib/commonjs/components/MainComponents/LoginWrapper.js +2 -1
  16. package/lib/commonjs/components/MainComponents/LoginWrapper.js.map +1 -1
  17. package/lib/commonjs/components/MainComponents/MediaMessage.js +29 -9
  18. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  19. package/lib/commonjs/components/MainComponents/MessageContainer.js +5 -1
  20. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  21. package/lib/commonjs/components/MainComponents/MessageList.js +13 -5
  22. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  23. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +14 -13
  24. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  25. package/lib/commonjs/components/MainComponents/RoomList.js +208 -35
  26. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  27. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +317 -98
  28. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  29. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +322 -110
  30. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  31. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +546 -203
  32. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  33. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
  34. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  35. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +69 -27
  36. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +2 -1
  38. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  39. package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
  40. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  41. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js +2 -1
  42. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  43. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -106
  44. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  45. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
  46. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  47. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +563 -0
  48. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  49. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
  50. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  51. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  52. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  53. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js +7 -21
  54. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  55. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
  56. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  57. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
  58. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  59. package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
  60. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  61. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +21 -7
  62. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  63. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +22 -3
  64. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  65. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
  66. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  67. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +17 -3
  68. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  69. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +6 -3
  70. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  71. package/lib/commonjs/components/styled/AudioMessage.js +2 -1
  72. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  73. package/lib/commonjs/components/styled/MessageImage.js +37 -9
  74. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  75. package/lib/commonjs/components/styled/SendInput.js +80 -11
  76. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  77. package/lib/commonjs/components/styled/StyledComponents.js +9 -3
  78. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  79. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  80. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  81. package/lib/commonjs/components/styled/UnsupportedType.js +14 -4
  82. package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
  83. package/lib/commonjs/components/styled/VideoMessage.js +119 -61
  84. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  85. package/lib/commonjs/context/xmppProvider.js +184 -59
  86. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  87. package/lib/commonjs/helpers/createMessageFromXml.js +19 -1
  88. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  89. package/lib/commonjs/helpers/ensureScopedChatCache.js +2 -2
  90. package/lib/commonjs/helpers/ensureScopedChatCache.js.map +1 -1
  91. package/lib/commonjs/helpers/getChatBackground.js +23 -0
  92. package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
  93. package/lib/commonjs/helpers/getDisplayFileName.js +79 -0
  94. package/lib/commonjs/helpers/getDisplayFileName.js.map +1 -0
  95. package/lib/commonjs/helpers/getServerReadTimestamp.js +188 -0
  96. package/lib/commonjs/helpers/getServerReadTimestamp.js.map +1 -0
  97. package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
  98. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  99. package/lib/commonjs/helpers/initXmppRooms.js +14 -8
  100. package/lib/commonjs/helpers/initXmppRooms.js.map +1 -1
  101. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +51 -9
  102. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  103. package/lib/commonjs/helpers/isOwnMessage.js +75 -0
  104. package/lib/commonjs/helpers/isOwnMessage.js.map +1 -0
  105. package/lib/commonjs/helpers/keyboardLayout.js +12 -2
  106. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
  107. package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
  108. package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
  109. package/lib/commonjs/helpers/mimeToExtension.js +6 -14
  110. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  111. package/lib/commonjs/helpers/msgSortableMs.js +37 -0
  112. package/lib/commonjs/helpers/msgSortableMs.js.map +1 -0
  113. package/lib/commonjs/helpers/persistCrypto.js +122 -0
  114. package/lib/commonjs/helpers/persistCrypto.js.map +1 -0
  115. package/lib/commonjs/helpers/pickImageAsset.js +68 -0
  116. package/lib/commonjs/helpers/pickImageAsset.js.map +1 -0
  117. package/lib/commonjs/helpers/pushPayload.js +71 -0
  118. package/lib/commonjs/helpers/pushPayload.js.map +1 -0
  119. package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +130 -17
  120. package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
  121. package/lib/commonjs/helpers/secureFileUrl.js +101 -0
  122. package/lib/commonjs/helpers/secureFileUrl.js.map +1 -0
  123. package/lib/commonjs/helpers/secureKeyValue.js +83 -0
  124. package/lib/commonjs/helpers/secureKeyValue.js.map +1 -0
  125. package/lib/commonjs/helpers/secureStoreRuntime.js +59 -0
  126. package/lib/commonjs/helpers/secureStoreRuntime.js.map +1 -0
  127. package/lib/commonjs/helpers/secureUserStorage.js +75 -0
  128. package/lib/commonjs/helpers/secureUserStorage.js.map +1 -0
  129. package/lib/commonjs/helpers/shallowEqual.js +36 -0
  130. package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
  131. package/lib/commonjs/helpers/sheetGestures.js +32 -0
  132. package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
  133. package/lib/commonjs/hooks/useChatRoomFocus.js +45 -12
  134. package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
  135. package/lib/commonjs/hooks/useChatWrapperInit.js +30 -10
  136. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  137. package/lib/commonjs/hooks/useComposing.js +27 -0
  138. package/lib/commonjs/hooks/useComposing.js.map +1 -1
  139. package/lib/commonjs/hooks/useFileToken.js +10 -0
  140. package/lib/commonjs/hooks/useFileToken.js.map +1 -0
  141. package/lib/commonjs/hooks/useLogout.js +23 -7
  142. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  143. package/lib/commonjs/hooks/usePendingNotification.js +8 -11
  144. package/lib/commonjs/hooks/usePendingNotification.js.map +1 -1
  145. package/lib/commonjs/hooks/useSendMessage.js +50 -14
  146. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  147. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
  148. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  149. package/lib/commonjs/i18n/strings.js +145 -37
  150. package/lib/commonjs/i18n/strings.js.map +1 -1
  151. package/lib/commonjs/main.js +44 -0
  152. package/lib/commonjs/main.js.map +1 -1
  153. package/lib/commonjs/networking/api-requests/auth.api.js +134 -60
  154. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  155. package/lib/commonjs/networking/api-requests/roomMembers.api.js +1 -1
  156. package/lib/commonjs/networking/api-requests/roomMembers.api.js.map +1 -1
  157. package/lib/commonjs/networking/api-requests/rooms.api.js +9 -9
  158. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  159. package/lib/commonjs/networking/api-requests/user.api.js +68 -9
  160. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  161. package/lib/commonjs/networking/apiClient.js +62 -112
  162. package/lib/commonjs/networking/apiClient.js.map +1 -1
  163. package/lib/commonjs/networking/authRefresh.js +332 -0
  164. package/lib/commonjs/networking/authRefresh.js.map +1 -0
  165. package/lib/commonjs/networking/stanzaHandlers.js +41 -28
  166. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  167. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
  168. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  169. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +8 -1
  170. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  171. package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
  172. package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
  173. package/lib/commonjs/networking/xmppClient.js +124 -8
  174. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  175. package/lib/commonjs/roomStore/chatSettingsSlice.js +26 -7
  176. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  177. package/lib/commonjs/roomStore/index.js +35 -2
  178. package/lib/commonjs/roomStore/index.js.map +1 -1
  179. package/lib/commonjs/roomStore/persistence.js +226 -23
  180. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  181. package/lib/commonjs/roomStore/roomsSlice.js +151 -38
  182. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  183. package/lib/commonjs/services/pushSubscriptionService.js +15 -13
  184. package/lib/commonjs/services/pushSubscriptionService.js.map +1 -1
  185. package/lib/commonjs/version.js +1 -1
  186. package/lib/module/assets/icons.js +6 -1
  187. package/lib/module/assets/icons.js.map +1 -1
  188. package/lib/module/components/AuthForms/Login.js +4 -4
  189. package/lib/module/components/AuthForms/Login.js.map +1 -1
  190. package/lib/module/components/Header/HeaderRoomList.js +29 -8
  191. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  192. package/lib/module/components/MainComponents/ChatHeader.js +9 -3
  193. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  194. package/lib/module/components/MainComponents/ChatRoom.js +152 -16
  195. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  196. package/lib/module/components/MainComponents/ChatWrapper.js +35 -14
  197. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  198. package/lib/module/components/MainComponents/LoginWrapper.js +2 -1
  199. package/lib/module/components/MainComponents/LoginWrapper.js.map +1 -1
  200. package/lib/module/components/MainComponents/MediaMessage.js +30 -10
  201. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  202. package/lib/module/components/MainComponents/MessageContainer.js +5 -1
  203. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  204. package/lib/module/components/MainComponents/MessageList.js +13 -5
  205. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  206. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +14 -13
  207. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  208. package/lib/module/components/MainComponents/RoomList.js +207 -35
  209. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  210. package/lib/module/components/Menu/HeaderRoomListMenu.js +319 -101
  211. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  212. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +313 -113
  213. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  214. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +549 -207
  215. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  216. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
  217. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  218. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +70 -28
  219. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  220. package/lib/module/components/Modals/FilePreviewModal/PdfView.js +2 -1
  221. package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  222. package/lib/module/components/Modals/Modal/Modal.js +9 -1
  223. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  224. package/lib/module/components/Modals/NewChatModal/ModalContent.js +2 -1
  225. package/lib/module/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  226. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -108
  227. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  228. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
  229. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  230. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +555 -0
  231. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  232. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
  233. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  234. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  235. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  236. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js +9 -23
  237. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  238. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
  239. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  240. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
  241. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  242. package/lib/module/components/Modals/styledModalComponents.js +9 -2
  243. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  244. package/lib/module/components/RoomComponents/ChatRoomItem.js +21 -7
  245. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  246. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +22 -3
  247. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  248. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
  249. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  250. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +17 -3
  251. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  252. package/lib/module/components/VideoCalls/VideoCallSession.js +6 -3
  253. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  254. package/lib/module/components/styled/AudioMessage.js +2 -1
  255. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  256. package/lib/module/components/styled/MessageImage.js +37 -9
  257. package/lib/module/components/styled/MessageImage.js.map +1 -1
  258. package/lib/module/components/styled/SendInput.js +81 -12
  259. package/lib/module/components/styled/SendInput.js.map +1 -1
  260. package/lib/module/components/styled/StyledComponents.js +9 -3
  261. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  262. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  263. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  264. package/lib/module/components/styled/UnsupportedType.js +14 -4
  265. package/lib/module/components/styled/UnsupportedType.js.map +1 -1
  266. package/lib/module/components/styled/VideoMessage.js +120 -62
  267. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  268. package/lib/module/context/xmppProvider.js +184 -60
  269. package/lib/module/context/xmppProvider.js.map +1 -1
  270. package/lib/module/helpers/createMessageFromXml.js +19 -1
  271. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  272. package/lib/module/helpers/ensureScopedChatCache.js +2 -2
  273. package/lib/module/helpers/ensureScopedChatCache.js.map +1 -1
  274. package/lib/module/helpers/getChatBackground.js +18 -0
  275. package/lib/module/helpers/getChatBackground.js.map +1 -0
  276. package/lib/module/helpers/getDisplayFileName.js +73 -0
  277. package/lib/module/helpers/getDisplayFileName.js.map +1 -0
  278. package/lib/module/helpers/getServerReadTimestamp.js +181 -0
  279. package/lib/module/helpers/getServerReadTimestamp.js.map +1 -0
  280. package/lib/module/helpers/historyPreloadScheduler.js +66 -3
  281. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  282. package/lib/module/helpers/initXmppRooms.js +14 -8
  283. package/lib/module/helpers/initXmppRooms.js.map +1 -1
  284. package/lib/module/helpers/insertMessageWithDelimiter.js +52 -9
  285. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  286. package/lib/module/helpers/isOwnMessage.js +70 -0
  287. package/lib/module/helpers/isOwnMessage.js.map +1 -0
  288. package/lib/module/helpers/keyboardLayout.js +12 -2
  289. package/lib/module/helpers/keyboardLayout.js.map +1 -1
  290. package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
  291. package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
  292. package/lib/module/helpers/mimeToExtension.js +6 -13
  293. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  294. package/lib/module/helpers/msgSortableMs.js +32 -0
  295. package/lib/module/helpers/msgSortableMs.js.map +1 -0
  296. package/lib/module/helpers/persistCrypto.js +115 -0
  297. package/lib/module/helpers/persistCrypto.js.map +1 -0
  298. package/lib/module/helpers/pickImageAsset.js +63 -0
  299. package/lib/module/helpers/pickImageAsset.js.map +1 -0
  300. package/lib/module/helpers/pushPayload.js +63 -0
  301. package/lib/module/helpers/pushPayload.js.map +1 -0
  302. package/lib/module/helpers/resolveInitBeforeLoadUser.js +130 -16
  303. package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
  304. package/lib/module/helpers/secureFileUrl.js +91 -0
  305. package/lib/module/helpers/secureFileUrl.js.map +1 -0
  306. package/lib/module/helpers/secureKeyValue.js +75 -0
  307. package/lib/module/helpers/secureKeyValue.js.map +1 -0
  308. package/lib/module/helpers/secureStoreRuntime.js +52 -0
  309. package/lib/module/helpers/secureStoreRuntime.js.map +1 -0
  310. package/lib/module/helpers/secureUserStorage.js +72 -0
  311. package/lib/module/helpers/secureUserStorage.js.map +1 -0
  312. package/lib/module/helpers/shallowEqual.js +31 -0
  313. package/lib/module/helpers/shallowEqual.js.map +1 -0
  314. package/lib/module/helpers/sheetGestures.js +26 -0
  315. package/lib/module/helpers/sheetGestures.js.map +1 -0
  316. package/lib/module/hooks/useChatRoomFocus.js +46 -13
  317. package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
  318. package/lib/module/hooks/useChatWrapperInit.js +30 -10
  319. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  320. package/lib/module/hooks/useComposing.js +28 -1
  321. package/lib/module/hooks/useComposing.js.map +1 -1
  322. package/lib/module/hooks/useFileToken.js +5 -0
  323. package/lib/module/hooks/useFileToken.js.map +1 -0
  324. package/lib/module/hooks/useLogout.js +23 -7
  325. package/lib/module/hooks/useLogout.js.map +1 -1
  326. package/lib/module/hooks/usePendingNotification.js +8 -11
  327. package/lib/module/hooks/usePendingNotification.js.map +1 -1
  328. package/lib/module/hooks/useSendMessage.js +52 -16
  329. package/lib/module/hooks/useSendMessage.js.map +1 -1
  330. package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
  331. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  332. package/lib/module/i18n/strings.js +145 -37
  333. package/lib/module/i18n/strings.js.map +1 -1
  334. package/lib/module/main.js +14 -2
  335. package/lib/module/main.js.map +1 -1
  336. package/lib/module/networking/api-requests/auth.api.js +131 -59
  337. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  338. package/lib/module/networking/api-requests/roomMembers.api.js +1 -1
  339. package/lib/module/networking/api-requests/roomMembers.api.js.map +1 -1
  340. package/lib/module/networking/api-requests/rooms.api.js +9 -9
  341. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  342. package/lib/module/networking/api-requests/user.api.js +64 -7
  343. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  344. package/lib/module/networking/apiClient.js +61 -113
  345. package/lib/module/networking/apiClient.js.map +1 -1
  346. package/lib/module/networking/authRefresh.js +321 -0
  347. package/lib/module/networking/authRefresh.js.map +1 -0
  348. package/lib/module/networking/stanzaHandlers.js +41 -28
  349. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  350. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
  351. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  352. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +8 -1
  353. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  354. package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
  355. package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
  356. package/lib/module/networking/xmppClient.js +124 -8
  357. package/lib/module/networking/xmppClient.js.map +1 -1
  358. package/lib/module/roomStore/chatSettingsSlice.js +26 -7
  359. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  360. package/lib/module/roomStore/index.js +37 -4
  361. package/lib/module/roomStore/index.js.map +1 -1
  362. package/lib/module/roomStore/persistence.js +223 -22
  363. package/lib/module/roomStore/persistence.js.map +1 -1
  364. package/lib/module/roomStore/roomsSlice.js +139 -34
  365. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  366. package/lib/module/services/pushSubscriptionService.js +15 -13
  367. package/lib/module/services/pushSubscriptionService.js.map +1 -1
  368. package/lib/module/version.js +1 -1
  369. package/lib/typescript/assets/icons.d.ts +16 -0
  370. package/lib/typescript/assets/icons.d.ts.map +1 -1
  371. package/lib/typescript/components/AuthForms/Login.d.ts.map +1 -1
  372. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  373. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  374. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  375. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  376. package/lib/typescript/components/MainComponents/LoginWrapper.d.ts.map +1 -1
  377. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  378. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  379. package/lib/typescript/components/MainComponents/MessageList.d.ts +10 -1
  380. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  381. package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
  382. package/lib/typescript/components/MainComponents/RoomList.d.ts +7 -0
  383. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  384. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +3 -0
  385. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  386. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
  387. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  388. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
  389. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  390. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
  391. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
  392. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  393. package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
  394. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  395. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts +4 -2
  396. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts.map +1 -1
  397. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
  398. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
  399. package/lib/typescript/components/Modals/NewChatModal/UpdNewChatModal.d.ts.map +1 -1
  400. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
  401. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
  402. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
  403. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
  404. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
  405. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  406. package/lib/typescript/components/Modals/UserProfileModal/EditUserModal.d.ts.map +1 -1
  407. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
  408. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  409. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
  410. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  411. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  412. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  413. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +1 -1
  414. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  415. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +1 -1
  416. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  417. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +1 -1
  418. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  419. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  420. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  421. package/lib/typescript/components/styled/MessageImage.d.ts +14 -0
  422. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  423. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  424. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  425. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  426. package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
  427. package/lib/typescript/components/styled/VideoMessage.d.ts +8 -0
  428. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  429. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  430. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  431. package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
  432. package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
  433. package/lib/typescript/helpers/getDisplayFileName.d.ts +49 -0
  434. package/lib/typescript/helpers/getDisplayFileName.d.ts.map +1 -0
  435. package/lib/typescript/helpers/getServerReadTimestamp.d.ts +108 -0
  436. package/lib/typescript/helpers/getServerReadTimestamp.d.ts.map +1 -0
  437. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  438. package/lib/typescript/helpers/initXmppRooms.d.ts.map +1 -1
  439. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts +1 -1
  440. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  441. package/lib/typescript/helpers/isOwnMessage.d.ts +36 -0
  442. package/lib/typescript/helpers/isOwnMessage.d.ts.map +1 -0
  443. package/lib/typescript/helpers/keyboardLayout.d.ts +5 -1
  444. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
  445. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
  446. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
  447. package/lib/typescript/helpers/mimeToExtension.d.ts +0 -15
  448. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  449. package/lib/typescript/helpers/msgSortableMs.d.ts +2 -0
  450. package/lib/typescript/helpers/msgSortableMs.d.ts.map +1 -0
  451. package/lib/typescript/helpers/persistCrypto.d.ts +13 -0
  452. package/lib/typescript/helpers/persistCrypto.d.ts.map +1 -0
  453. package/lib/typescript/helpers/pickImageAsset.d.ts +27 -0
  454. package/lib/typescript/helpers/pickImageAsset.d.ts.map +1 -0
  455. package/lib/typescript/helpers/pushPayload.d.ts +7 -0
  456. package/lib/typescript/helpers/pushPayload.d.ts.map +1 -0
  457. package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
  458. package/lib/typescript/helpers/secureFileUrl.d.ts +7 -0
  459. package/lib/typescript/helpers/secureFileUrl.d.ts.map +1 -0
  460. package/lib/typescript/helpers/secureKeyValue.d.ts +13 -0
  461. package/lib/typescript/helpers/secureKeyValue.d.ts.map +1 -0
  462. package/lib/typescript/helpers/secureStoreRuntime.d.ts +29 -0
  463. package/lib/typescript/helpers/secureStoreRuntime.d.ts.map +1 -0
  464. package/lib/typescript/helpers/secureUserStorage.d.ts +23 -0
  465. package/lib/typescript/helpers/secureUserStorage.d.ts.map +1 -0
  466. package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
  467. package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
  468. package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
  469. package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
  470. package/lib/typescript/hooks/useChatRoomFocus.d.ts +4 -1
  471. package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
  472. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  473. package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
  474. package/lib/typescript/hooks/useFileToken.d.ts +2 -0
  475. package/lib/typescript/hooks/useFileToken.d.ts.map +1 -0
  476. package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
  477. package/lib/typescript/hooks/usePendingNotification.d.ts.map +1 -1
  478. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  479. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
  480. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  481. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  482. package/lib/typescript/main.d.ts +9 -2
  483. package/lib/typescript/main.d.ts.map +1 -1
  484. package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -1
  485. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  486. package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
  487. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  488. package/lib/typescript/networking/apiClient.d.ts +12 -6
  489. package/lib/typescript/networking/apiClient.d.ts.map +1 -1
  490. package/lib/typescript/networking/authRefresh.d.ts +95 -0
  491. package/lib/typescript/networking/authRefresh.d.ts.map +1 -0
  492. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  493. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +10 -2
  494. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  495. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  496. package/lib/typescript/networking/xmpp/subscribeToRoomMessages.xmpp.d.ts.map +1 -1
  497. package/lib/typescript/networking/xmppClient.d.ts +14 -0
  498. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  499. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +16 -0
  500. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  501. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  502. package/lib/typescript/roomStore/persistence.d.ts +18 -1
  503. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  504. package/lib/typescript/roomStore/roomsSlice.d.ts +43 -3
  505. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  506. package/lib/typescript/services/pushSubscriptionService.d.ts +1 -1
  507. package/lib/typescript/services/pushSubscriptionService.d.ts.map +1 -1
  508. package/lib/typescript/types/types.d.ts +50 -5
  509. package/lib/typescript/types/types.d.ts.map +1 -1
  510. package/lib/typescript/version.d.ts +1 -1
  511. package/package.json +41 -28
  512. package/src/assets/icons.tsx +48 -9
  513. package/src/components/AuthForms/Login.tsx +3 -3
  514. package/src/components/Header/HeaderRoomList.tsx +29 -7
  515. package/src/components/MainComponents/ChatHeader.tsx +9 -3
  516. package/src/components/MainComponents/ChatRoom.tsx +161 -15
  517. package/src/components/MainComponents/ChatWrapper.tsx +36 -20
  518. package/src/components/MainComponents/LoginWrapper.tsx +1 -0
  519. package/src/components/MainComponents/MediaMessage.tsx +26 -8
  520. package/src/components/MainComponents/MessageContainer.tsx +5 -1
  521. package/src/components/MainComponents/MessageList.tsx +23 -4
  522. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +21 -14
  523. package/src/components/MainComponents/RoomList.tsx +236 -39
  524. package/src/components/Menu/HeaderRoomListMenu.tsx +328 -75
  525. package/src/components/Modals/AttachSheet/AttachSheet.tsx +333 -97
  526. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +600 -282
  527. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
  528. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +79 -38
  529. package/src/components/Modals/FilePreviewModal/PdfView.tsx +2 -1
  530. package/src/components/Modals/Modal/Modal.tsx +7 -0
  531. package/src/components/Modals/NewChatModal/ModalContent.tsx +6 -3
  532. package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -119
  533. package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +12 -1
  534. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +624 -0
  535. package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
  536. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
  537. package/src/components/Modals/UserProfileModal/EditUserModal.tsx +9 -25
  538. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
  539. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
  540. package/src/components/Modals/styledModalComponents.tsx +9 -2
  541. package/src/components/RoomComponents/ChatRoomItem.tsx +18 -3
  542. package/src/components/RoomComponents/styled/LastMessageFile.tsx +28 -4
  543. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +18 -3
  544. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +18 -3
  545. package/src/components/VideoCalls/VideoCallSession.tsx +8 -3
  546. package/src/components/styled/AudioMessage.tsx +2 -1
  547. package/src/components/styled/MessageImage.tsx +53 -7
  548. package/src/components/styled/SendInput.tsx +83 -12
  549. package/src/components/styled/StyledComponents.ts +9 -3
  550. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
  551. package/src/components/styled/UnsupportedType.tsx +14 -4
  552. package/src/components/styled/VideoMessage.tsx +131 -54
  553. package/src/context/xmppProvider.tsx +216 -57
  554. package/src/helpers/createMessageFromXml.ts +20 -1
  555. package/src/helpers/ensureScopedChatCache.ts +2 -2
  556. package/src/helpers/getChatBackground.ts +18 -0
  557. package/src/helpers/getDisplayFileName.ts +87 -0
  558. package/src/helpers/getServerReadTimestamp.ts +197 -0
  559. package/src/helpers/historyPreloadScheduler.ts +80 -3
  560. package/src/helpers/initXmppRooms.tsx +14 -10
  561. package/src/helpers/insertMessageWithDelimiter.ts +55 -19
  562. package/src/helpers/isOwnMessage.ts +90 -0
  563. package/src/helpers/keyboardLayout.ts +23 -2
  564. package/src/helpers/mediaLibraryRuntime.ts +25 -0
  565. package/src/helpers/mimeToExtension.ts +6 -22
  566. package/src/helpers/msgSortableMs.ts +25 -0
  567. package/src/helpers/persistCrypto.ts +127 -0
  568. package/src/helpers/pickImageAsset.ts +68 -0
  569. package/src/helpers/pushPayload.ts +62 -0
  570. package/src/helpers/resolveInitBeforeLoadUser.ts +125 -18
  571. package/src/helpers/secureFileUrl.ts +103 -0
  572. package/src/helpers/secureKeyValue.ts +80 -0
  573. package/src/helpers/secureStoreRuntime.ts +62 -0
  574. package/src/helpers/secureUserStorage.ts +80 -0
  575. package/src/helpers/shallowEqual.ts +33 -0
  576. package/src/helpers/sheetGestures.ts +25 -0
  577. package/src/hooks/useChatRoomFocus.ts +49 -9
  578. package/src/hooks/useChatWrapperInit.ts +30 -10
  579. package/src/hooks/useComposing.tsx +37 -1
  580. package/src/hooks/useFileToken.ts +7 -0
  581. package/src/hooks/useLogout.tsx +29 -9
  582. package/src/hooks/usePendingNotification.ts +5 -11
  583. package/src/hooks/useSendMessage.tsx +60 -15
  584. package/src/hooks/useUnreadMessagesCounter.ts +11 -0
  585. package/src/i18n/strings.ts +145 -37
  586. package/src/main.ts +26 -2
  587. package/src/networking/api-requests/auth.api.ts +156 -48
  588. package/src/networking/api-requests/roomMembers.api.ts +1 -1
  589. package/src/networking/api-requests/rooms.api.ts +9 -9
  590. package/src/networking/api-requests/user.api.ts +79 -7
  591. package/src/networking/apiClient.ts +68 -123
  592. package/src/networking/authRefresh.ts +451 -0
  593. package/src/networking/stanzaHandlers.ts +44 -28
  594. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +71 -10
  595. package/src/networking/xmpp/presenceInRoom.xmpp.ts +6 -1
  596. package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +12 -1
  597. package/src/networking/xmppClient.ts +141 -9
  598. package/src/roomStore/chatSettingsSlice.ts +34 -10
  599. package/src/roomStore/index.ts +40 -4
  600. package/src/roomStore/persistence.ts +234 -24
  601. package/src/roomStore/roomsSlice.ts +161 -29
  602. package/src/services/pushSubscriptionService.ts +18 -13
  603. package/src/types/types.ts +72 -5
  604. package/src/version.ts +1 -1
@@ -0,0 +1,127 @@
1
+ import CryptoJS from 'crypto-js';
2
+ import { secureGet, secureSet } from './secureKeyValue';
3
+
4
+ // AES-256-CBC at rest for the bulk persisted state (message history +
5
+ // room list) that `roomStore/persistence.ts` writes to AsyncStorage.
6
+ // This is envelope encryption, not a SecureStore write of the payload
7
+ // itself: expo-secure-store has historically capped a single value's
8
+ // size on Android (chunking exists in newer releases, but the payload
9
+ // here is unbounded — up to MESSAGE_LIMIT messages per room, times
10
+ // every room), so only the small symmetric KEY goes through the
11
+ // platform Keychain/Keystore (`secureKeyValue.ts`); the ciphertext
12
+ // itself stays in plain AsyncStorage, unreadable without that key.
13
+ const CIPHER_KEY_STORE_KEY = 'ethora_history_cipher_key';
14
+ const ENVELOPE_VERSION = 1;
15
+ const KEY_BYTES = 32; // AES-256
16
+ const IV_BYTES = 16; // one AES block
17
+
18
+ interface Envelope {
19
+ v: number;
20
+ iv: string; // base64
21
+ ct: string; // base64 ciphertext
22
+ }
23
+
24
+ /**
25
+ * `crypto-js`'s own `WordArray.random()` falls back to `Math.random()`
26
+ * when it can't detect a browser `window.crypto` — not safe for key/IV
27
+ * material. `react-native-get-random-values` (a REQUIRED peer
28
+ * dependency, imported at the top of `main.ts`/`index.js` before
29
+ * anything else in the SDK runs) polyfills the real thing onto
30
+ * `global.crypto.getRandomValues` instead; source bytes from that and
31
+ * hand them to crypto-js as a WordArray rather than trust its default.
32
+ */
33
+ const randomWordArray = (byteLength: number): CryptoJS.lib.WordArray => {
34
+ const bytes = new Uint8Array(byteLength);
35
+ (global as any).crypto.getRandomValues(bytes);
36
+ const words: number[] = [];
37
+ for (let i = 0; i < bytes.length; i += 4) {
38
+ words.push(
39
+ ((bytes[i] || 0) << 24) |
40
+ ((bytes[i + 1] || 0) << 16) |
41
+ ((bytes[i + 2] || 0) << 8) |
42
+ (bytes[i + 3] || 0)
43
+ );
44
+ }
45
+ return CryptoJS.lib.WordArray.create(words, byteLength);
46
+ };
47
+
48
+ let cachedKeyPromise: Promise<CryptoJS.lib.WordArray> | null = null;
49
+
50
+ /**
51
+ * One AES-256 key per install, generated on first use and persisted
52
+ * through the SecureStore/Keychain bridge. Reused across logins on
53
+ * purpose: the ciphertext it protects is deleted wholesale on logout
54
+ * (`clearPersistedState`), so there is no cross-account data for a
55
+ * stable key to expose — only the encrypted blob of whoever is
56
+ * currently logged in ever exists on disk at a given time.
57
+ */
58
+ const loadOrCreateKey = (): Promise<CryptoJS.lib.WordArray> => {
59
+ if (cachedKeyPromise) {return cachedKeyPromise;}
60
+ cachedKeyPromise = (async () => {
61
+ const existing = await secureGet(CIPHER_KEY_STORE_KEY);
62
+ if (existing) {
63
+ return CryptoJS.enc.Base64.parse(existing);
64
+ }
65
+ const key = randomWordArray(KEY_BYTES);
66
+ await secureSet(CIPHER_KEY_STORE_KEY, CryptoJS.enc.Base64.stringify(key));
67
+ return key;
68
+ })();
69
+ return cachedKeyPromise;
70
+ };
71
+
72
+ /** Encrypt a JSON-serialisable payload for storage. Returns the string to persist. */
73
+ export async function encryptForPersist(plaintext: string): Promise<string> {
74
+ const key = await loadOrCreateKey();
75
+ const iv = randomWordArray(IV_BYTES);
76
+ const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
77
+ iv,
78
+ mode: CryptoJS.mode.CBC,
79
+ padding: CryptoJS.pad.Pkcs7,
80
+ });
81
+ const envelope: Envelope = {
82
+ v: ENVELOPE_VERSION,
83
+ iv: CryptoJS.enc.Base64.stringify(iv),
84
+ ct: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
85
+ };
86
+ return JSON.stringify(envelope);
87
+ }
88
+
89
+ /**
90
+ * Decrypt a value previously written by `encryptForPersist`. Returns
91
+ * null (never throws) for anything that isn't a valid envelope for the
92
+ * current key — including a plaintext blob from a pre-encryption
93
+ * install: the app just re-hydrates that room/history from the server,
94
+ * same as any other empty-cache cold start.
95
+ */
96
+ export async function decryptFromPersist(
97
+ stored: string
98
+ ): Promise<string | null> {
99
+ try {
100
+ const envelope = JSON.parse(stored) as Partial<Envelope>;
101
+ if (
102
+ !envelope ||
103
+ envelope.v !== ENVELOPE_VERSION ||
104
+ !envelope.iv ||
105
+ !envelope.ct
106
+ ) {
107
+ return null;
108
+ }
109
+ const key = await loadOrCreateKey();
110
+ const iv = CryptoJS.enc.Base64.parse(envelope.iv);
111
+ const ciphertext = CryptoJS.enc.Base64.parse(envelope.ct);
112
+ const decrypted = CryptoJS.AES.decrypt(
113
+ { ciphertext } as CryptoJS.lib.CipherParams,
114
+ key,
115
+ { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
116
+ );
117
+ const plaintext = decrypted.toString(CryptoJS.enc.Utf8);
118
+ return plaintext || null;
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+
124
+ /** Test seam only. */
125
+ export const __resetPersistCryptoKeyForTests = (): void => {
126
+ cachedKeyPromise = null;
127
+ };
@@ -0,0 +1,68 @@
1
+ import { Alert, Linking } from 'react-native';
2
+ import * as ImagePicker from 'expo-image-picker';
3
+
4
+ /**
5
+ * A picked image in the shape React Native's FormData understands.
6
+ *
7
+ * NOT a web `File`: RN streams a multipart part straight from a `file://`
8
+ * uri and has no usable Blob/File/atob path. Screens ported from the web
9
+ * client used to carry base64 -> Blob -> File helpers that could never
10
+ * have run here.
11
+ */
12
+ export interface PickedImage {
13
+ uri: string;
14
+ type: string;
15
+ name: string;
16
+ }
17
+
18
+ /**
19
+ * Ask for library permission, open the picker, and normalise the result.
20
+ *
21
+ * Returns `null` for every non-error outcome — permission refused, user
22
+ * cancelled — so call sites can simply keep their current value.
23
+ *
24
+ * Exists because the avatar pickers are wired to `onPress`, which hands
25
+ * the callback a SyntheticEvent. Storing that event as "the image" (what
26
+ * two screens used to do) rendered a pooled event as an <Image source>
27
+ * and then crashed with "Property is not configurable" when React tried
28
+ * to release it — on top of never letting the user pick anything.
29
+ */
30
+ export const pickImageAsset = async (): Promise<PickedImage | null> => {
31
+ try {
32
+ // expo-image-picker owns the permission prompt internally and
33
+ // returns a `granted` flag.
34
+ const perm = await ImagePicker.requestMediaLibraryPermissionsAsync();
35
+ if (!perm.granted) {
36
+ Alert.alert(
37
+ 'Permission required',
38
+ 'Photo library permission is needed to select images.',
39
+ [
40
+ { text: 'Cancel', style: 'cancel' },
41
+ { text: 'Open Settings', onPress: () => Linking.openSettings() },
42
+ ]
43
+ );
44
+ return null;
45
+ }
46
+
47
+ const result = await ImagePicker.launchImageLibraryAsync({
48
+ mediaTypes: ['images'],
49
+ allowsEditing: true,
50
+ aspect: [1, 1],
51
+ quality: 0.8,
52
+ });
53
+ if (result.canceled || !result.assets?.[0]) {
54
+ return null;
55
+ }
56
+
57
+ const asset = result.assets[0];
58
+ const originalName = asset.fileName || asset.uri.split('/').pop();
59
+ return {
60
+ uri: asset.uri,
61
+ type: asset.mimeType || 'image/jpeg',
62
+ name: originalName || `image_${Date.now()}.jpg`,
63
+ };
64
+ } catch (error) {
65
+ console.error('Failed to pick an image:', error);
66
+ return null;
67
+ }
68
+ };
@@ -0,0 +1,62 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { store } from '../roomStore';
3
+ import {
4
+ clearPendingNotificationJid,
5
+ setCurrentRoom,
6
+ setPendingNotificationJid,
7
+ } from '../roomStore/roomsSlice';
8
+ import { handleCallPush } from './incomingCallFromPush';
9
+ import { normalizeRoomJid } from './normalizeRoomJid';
10
+
11
+ export type PushPayloadOutcome = 'call' | 'room' | 'pending' | 'unknown';
12
+
13
+ export const PENDING_NOTIFICATION_JID_KEY = 'ethora_pending_notification_jid';
14
+ export const PENDING_NOTIFICATION_TTL_MS = 5 * 60 * 1000;
15
+
16
+ export const readPendingJid = async (): Promise<string | null> => {
17
+ try {
18
+ const raw = await AsyncStorage.getItem(PENDING_NOTIFICATION_JID_KEY);
19
+ if (!raw) {return null;}
20
+ if (raw.startsWith('{')) {
21
+ const { jid, at } = JSON.parse(raw) as { jid?: string; at?: number };
22
+ if (!jid || !at || Date.now() - at > PENDING_NOTIFICATION_TTL_MS) {
23
+ await AsyncStorage.removeItem(PENDING_NOTIFICATION_JID_KEY);
24
+ return null;
25
+ }
26
+ return jid;
27
+ }
28
+ return raw;
29
+ } catch {
30
+ return null;
31
+ }
32
+ };
33
+
34
+ export const openRoomFromPush = (jid: string): 'room' | 'pending' => {
35
+ const state = store.getState();
36
+ const conference = state.chatSettingStore?.config?.xmppSettings?.conference;
37
+ const full = normalizeRoomJid(jid, conference);
38
+
39
+ AsyncStorage.setItem(
40
+ PENDING_NOTIFICATION_JID_KEY,
41
+ JSON.stringify({ jid: full, at: Date.now() })
42
+ ).catch(() => undefined);
43
+ if (state.rooms?.rooms?.[full]) {
44
+ store.dispatch(clearPendingNotificationJid());
45
+ store.dispatch(setCurrentRoom({ roomJID: full }));
46
+ return 'room';
47
+ }
48
+ store.dispatch(setPendingNotificationJid(full));
49
+ return 'pending';
50
+ };
51
+
52
+ export const handlePushPayload = (
53
+ data: Record<string, unknown> | null | undefined
54
+ ): PushPayloadOutcome => {
55
+ if (!data) {return 'unknown';}
56
+ if (handleCallPush(data as Record<string, any>)) {return 'call';}
57
+ const jid = data.jid ?? data.chatJid ?? data.roomJid ?? data.roomJID;
58
+ if (typeof jid === 'string' && jid) {
59
+ return openRoomFromPush(jid);
60
+ }
61
+ return 'unknown';
62
+ };
@@ -1,12 +1,12 @@
1
- import http, { setBaseURL } from '../networking/apiClient';
1
+ import { setBaseURL } from '../networking/apiClient';
2
+ import { refreshAuthTokens, isRefreshFatalError } from '../networking/authRefresh';
2
3
  import { loginViaJwt } from '../networking/api-requests/auth.api';
3
4
  import { getMyUser } from '../networking/api-requests/user.api';
4
5
  import { IConfig, User } from '../types/types';
5
6
  import { store } from '../roomStore';
6
7
  import { setUser } from '../roomStore/chatSettingsSlice';
7
8
  import { walletToUsername } from './walletUsername';
8
- import { asyncLocalStorage } from '../hooks/useLocalStorage';
9
- import { localStorageConstants } from './constants/LOCAL_STORAGE';
9
+ import { secureUserStorage } from './secureUserStorage';
10
10
 
11
11
  interface ResolveInitBeforeLoadUserOptions {
12
12
  config?: IConfig;
@@ -46,15 +46,107 @@ const normalizeUserForXmpp = (user?: User | null): User | null => {
46
46
  return { ...user, xmppUsername: normalizedXmppUsername };
47
47
  };
48
48
 
49
+ // Hermes has no atob/Buffer; hand-decode just enough base64url to read a
50
+ // JWT's `iat`. Claims are ASCII so the byte-per-char string is fine.
51
+ const B64_ALPHABET =
52
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
53
+
54
+ const readJwtIat = (token?: string | null): number => {
55
+ if (!token || typeof token !== 'string') {return 0;}
56
+ const part = token.split('.')[1];
57
+ if (!part) {return 0;}
58
+ try {
59
+ const clean = part.replace(/-/g, '+').replace(/_/g, '/');
60
+ let out = '';
61
+ let buffer = 0;
62
+ let bits = 0;
63
+ for (let i = 0; i < clean.length; i++) {
64
+ const idx = B64_ALPHABET.indexOf(clean[i]);
65
+ if (idx === -1) {continue;}
66
+ buffer = (buffer << 6) | idx;
67
+ bits += 6;
68
+ if (bits >= 8) {
69
+ bits -= 8;
70
+ out += String.fromCharCode((buffer >> bits) & 0xff);
71
+ }
72
+ }
73
+ const iat = JSON.parse(out)?.iat;
74
+ return typeof iat === 'number' ? iat : 0;
75
+ } catch {
76
+ return 0;
77
+ }
78
+ };
79
+
80
+ /**
81
+ * A `userLogin.user` is typically a snapshot the host captured at ITS
82
+ * login time and re-presents verbatim on every mount, while this SDK
83
+ * keeps rotating the session and persisting the newest pair to
84
+ * `ETHORA_USER`. Taking the snapshot as-is therefore discards the live
85
+ * session in favour of an ever-aging copy: media goes blank the moment
86
+ * the snapshot has no `fileToken` (secure-files URLs 401 without it),
87
+ * and once the snapshot's refresh token ages out entirely the account
88
+ * looks dead even though the SDK held a working session all along.
89
+ *
90
+ * So, for the SAME account only, prefer whichever refresh pair was
91
+ * minted later (JWT `iat` decides — a host that genuinely re-logged-in
92
+ * hands us newer tokens and wins), and fill in a missing `fileToken`
93
+ * from the persisted copy either way.
94
+ */
95
+ const adoptFresherPersistedSession = async (candidate: User): Promise<User> => {
96
+ try {
97
+ const stored = await secureUserStorage().get();
98
+ if (!stored) {return candidate;}
99
+
100
+ const sameUser =
101
+ (candidate._id && stored._id && candidate._id === stored._id) ||
102
+ (candidate.xmppUsername &&
103
+ stored.xmppUsername &&
104
+ candidate.xmppUsername === stored.xmppUsername);
105
+ if (!sameUser) {return candidate;}
106
+
107
+ const merged = { ...candidate };
108
+
109
+ if (
110
+ stored.refreshToken &&
111
+ readJwtIat(stored.refreshToken) > readJwtIat(candidate.refreshToken)
112
+ ) {
113
+ merged.refreshToken = stored.refreshToken;
114
+ if (stored.token) {merged.token = stored.token;}
115
+ if (stored.fileToken) {merged.fileToken = stored.fileToken;}
116
+ }
117
+
118
+ if (!merged.fileToken && stored.fileToken) {
119
+ merged.fileToken = stored.fileToken;
120
+ }
121
+
122
+ return merged;
123
+ } catch {
124
+ return candidate;
125
+ }
126
+ };
127
+
128
+ /**
129
+ * Bootstrap rotation.
130
+ *
131
+ * Was a second, independent `/users/login/refresh` caller that bypassed
132
+ * every lock in the SDK — and, worse, only wrote the rotated token to
133
+ * the store on the happy path, so several of the early-return branches
134
+ * below used to drop it. Under the backend's reuse detection a dropped
135
+ * rotation means the next launch presents a burned token and the
136
+ * session is killed.
137
+ *
138
+ * `refreshAuthTokens` persists the new pair before it resolves, so by
139
+ * the time this returns the rotation is safe no matter which branch the
140
+ * caller takes afterwards. The explicit token is required here: during
141
+ * bootstrap the candidate session isn't in the store yet.
142
+ */
49
143
  const refreshWithToken = async (refreshToken: string) => {
50
- const response = await http.post(
51
- '/users/login/refresh',
52
- {},
53
- { headers: { Authorization: refreshToken } }
54
- );
144
+ const result = await refreshAuthTokens({ refreshToken });
55
145
  return {
56
- token: response?.data?.token || '',
57
- refreshToken: response?.data?.refreshToken || refreshToken,
146
+ token: result.token,
147
+ refreshToken: result.refreshToken || refreshToken,
148
+ xmppPassword: result.xmppPassword || '',
149
+ fileToken: result.fileToken || '',
58
150
  };
59
151
  };
60
152
 
@@ -87,11 +179,15 @@ const tryHydrateViaMy = async (
87
179
 
88
180
  let workingToken = candidate?.token || '';
89
181
  let workingRefresh = candidate?.refreshToken || '';
182
+ let rotatedXmppPassword = '';
183
+ let workingFileToken = candidate?.fileToken || '';
90
184
 
91
185
  const candidateWithCurrentTokens = (): User => ({
92
186
  ...candidate,
93
187
  token: workingToken || candidate.token,
94
188
  refreshToken: workingRefresh || candidate.refreshToken,
189
+ xmppPassword: rotatedXmppPassword || candidate.xmppPassword,
190
+ fileToken: workingFileToken || candidate.fileToken,
95
191
  });
96
192
 
97
193
  const fallbackWithCreds = (): User | null => {
@@ -107,6 +203,8 @@ const tryHydrateViaMy = async (
107
203
  if (merged) {
108
204
  merged.token = workingToken || merged.token;
109
205
  merged.refreshToken = workingRefresh || merged.refreshToken;
206
+ merged.xmppPassword = rotatedXmppPassword || merged.xmppPassword;
207
+ merged.fileToken = workingFileToken || merged.fileToken;
110
208
  }
111
209
  return merged;
112
210
  } catch (error) {
@@ -127,6 +225,8 @@ const tryHydrateViaMy = async (
127
225
  const refreshed = await refreshWithToken(workingRefresh);
128
226
  workingToken = refreshed.token;
129
227
  workingRefresh = refreshed.refreshToken;
228
+ rotatedXmppPassword = refreshed.xmppPassword || rotatedXmppPassword;
229
+ workingFileToken = refreshed.fileToken || workingFileToken;
130
230
 
131
231
  try {
132
232
  const myUser = await getMyUser({ token: workingToken, endpoint: myEndpoint });
@@ -136,6 +236,8 @@ const tryHydrateViaMy = async (
136
236
  if (merged) {
137
237
  merged.token = workingToken || merged.token;
138
238
  merged.refreshToken = workingRefresh || merged.refreshToken;
239
+ merged.xmppPassword = rotatedXmppPassword || merged.xmppPassword;
240
+ merged.fileToken = workingFileToken || merged.fileToken;
139
241
  }
140
242
  return merged;
141
243
  } catch (myError) {
@@ -147,6 +249,11 @@ const tryHydrateViaMy = async (
147
249
  }
148
250
  } catch (error) {
149
251
  if (signal?.aborted || isAbortError(error)) {return null;}
252
+ // A fatal refresh verdict (reuse detected / token not found / stale
253
+ // with nothing newer around) carries no HTTP response, so it would
254
+ // otherwise fall through to `throw` — the session is simply dead,
255
+ // which for bootstrap means "nothing to restore".
256
+ if (isRefreshFatalError(error)) {return null;}
150
257
  if (isAuthError(error)) {return null;}
151
258
  throw error;
152
259
  }
@@ -162,13 +269,15 @@ export const resolveInitBeforeLoadUser = async (
162
269
  setBaseURL(config.baseUrl, config.customAppToken);
163
270
  }
164
271
 
165
- const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/users/my';
272
+ const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/v1/users/my';
166
273
 
167
274
  // Priority 1: explicit userLogin
168
275
  const explicitUser = config?.userLogin?.enabled ? config?.userLogin?.user : null;
169
276
  if (explicitUser) {
170
277
  const candidate = normalizeUserForXmpp(explicitUser);
171
- if (candidate && hasXmppCredentials(candidate)) {return candidate;}
278
+ if (candidate && hasXmppCredentials(candidate)) {
279
+ return await adoptFresherPersistedSession(candidate);
280
+ }
172
281
 
173
282
  const hydrated = await tryHydrateViaMy(explicitUser, myEndpoint, signal).catch(
174
283
  () => null
@@ -217,13 +326,13 @@ export const resolveInitBeforeLoadUser = async (
217
326
 
218
327
  // Priority 5: persisted user in AsyncStorage
219
328
  try {
220
- const storedUser = await asyncLocalStorage<User>(localStorageConstants.ETHORA_USER).get();
329
+ const storedUser = await secureUserStorage().get();
221
330
  if (storedUser && (storedUser.token || storedUser.refreshToken || storedUser.xmppPassword)) {
222
331
  const hydrated = await tryHydrateViaMy(storedUser, myEndpoint, signal).catch(
223
332
  () => null
224
333
  );
225
334
  if (hydrated && hasXmppCredentials(hydrated)) {return hydrated;}
226
- await asyncLocalStorage(localStorageConstants.ETHORA_USER).remove();
335
+ await secureUserStorage().remove();
227
336
  }
228
337
  } catch {
229
338
  // ignore storage errors
@@ -275,7 +384,7 @@ export const refreshUserCredentialsForXmpp = async (
275
384
  }
276
385
  }
277
386
 
278
- const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/users/my';
387
+ const myEndpoint = config?.initBeforeLoadAuth?.myEndpoint || '/v1/users/my';
279
388
 
280
389
  // Priority 2: redux store user (covers userLogin + customLogin +
281
390
  // anything previously persisted into chatSettingStore.user). The
@@ -295,9 +404,7 @@ export const refreshUserCredentialsForXmpp = async (
295
404
  // should already mirror this, but if the redux state got cleared
296
405
  // mid-session (logout race) this gives us one last shot.
297
406
  try {
298
- const storedUser = await asyncLocalStorage<User>(
299
- localStorageConstants.ETHORA_USER
300
- ).get();
407
+ const storedUser = await secureUserStorage().get();
301
408
  if (
302
409
  storedUser &&
303
410
  (storedUser.token || storedUser.refreshToken || storedUser.xmppPassword)
@@ -0,0 +1,103 @@
1
+ import { store } from '../roomStore';
2
+ import { getCurrentBaseURL } from '../networking/apiClient';
3
+ import { refreshAuthTokens } from '../networking/authRefresh';
4
+
5
+ const SECURE_FILES_HOST_PREFIX = 'secure-files.';
6
+ const SECURE_MEDIA_PATH_PREFIX = '/secure-media/';
7
+
8
+ const FILE_TOKEN_PARAM = 'ft';
9
+
10
+ export const resolveFileUrl = (url?: string | null): string => {
11
+ if (!url) {return '';}
12
+ // Any scheme at all — http(s), data, file, content, blob.
13
+ if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {return url;}
14
+ if (!url.startsWith('/')) {return url;}
15
+
16
+ const base = getCurrentBaseURL().replace(/\/+$/, '');
17
+ return base ? `${base}${url}` : url;
18
+ };
19
+
20
+ export const isSecureFileUrl = (url?: string | null): boolean => {
21
+ if (!url) {return false;}
22
+
23
+ const path = url.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i, '');
24
+ if (path.startsWith(SECURE_MEDIA_PATH_PREFIX)) {return true;}
25
+
26
+ const match = /^https?:\/\/(?:[^@/]+@)?([^:/?#]+)/i.exec(url);
27
+ if (!match) {return false;}
28
+ return match[1].toLowerCase().startsWith(SECURE_FILES_HOST_PREFIX);
29
+ };
30
+
31
+ export const appendFileToken = (
32
+ url: string | null | undefined,
33
+ fileToken: string | null | undefined
34
+ ): string => {
35
+ if (!url) {return '';}
36
+
37
+ const resolved = resolveFileUrl(url);
38
+ if (!fileToken || !isSecureFileUrl(resolved)) {return resolved;}
39
+ url = resolved;
40
+
41
+ const hashIndex = url.indexOf('#');
42
+ const hash = hashIndex === -1 ? '' : url.slice(hashIndex);
43
+ const withoutHash = hashIndex === -1 ? url : url.slice(0, hashIndex);
44
+
45
+ const queryIndex = withoutHash.indexOf('?');
46
+ const base = queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);
47
+ const query = queryIndex === -1 ? '' : withoutHash.slice(queryIndex + 1);
48
+
49
+ const params = query
50
+ .split('&')
51
+ .filter(Boolean)
52
+ .filter((pair) => pair.split('=')[0] !== FILE_TOKEN_PARAM);
53
+
54
+ params.push(`${FILE_TOKEN_PARAM}=${encodeURIComponent(fileToken)}`);
55
+
56
+ return `${base}?${params.join('&')}${hash}`;
57
+ };
58
+
59
+ export const withFileToken = (url?: string | null): string =>
60
+ appendFileToken(
61
+ url,
62
+ store.getState().chatSettingStore?.user?.fileToken || ''
63
+ );
64
+
65
+ const RECOVERY_COOLDOWN_MS = 30_000;
66
+ let recoveryInFlight: Promise<boolean> | null = null;
67
+ let lastRecoveryAt = 0;
68
+
69
+ export const requestFileTokenRecovery = (): Promise<boolean> => {
70
+ if (recoveryInFlight) {return recoveryInFlight;}
71
+
72
+ const now = Date.now();
73
+ if (now - lastRecoveryAt < RECOVERY_COOLDOWN_MS) {
74
+ return Promise.resolve(false);
75
+ }
76
+ lastRecoveryAt = now;
77
+
78
+ const state = store.getState();
79
+ const refreshConfig = state.chatSettingStore?.config?.refreshTokens;
80
+ const user = state.chatSettingStore?.user;
81
+
82
+ if (!refreshConfig?.enabled) {return Promise.resolve(false);}
83
+
84
+ const run = async (): Promise<boolean> => {
85
+ if (!refreshConfig.refreshFunction && !user?.refreshToken) {return false;}
86
+
87
+ const tokens = await refreshAuthTokens();
88
+ return Boolean(tokens.fileToken);
89
+ };
90
+
91
+ recoveryInFlight = run()
92
+ .catch(() => false)
93
+ .finally(() => {
94
+ recoveryInFlight = null;
95
+ });
96
+
97
+ return recoveryInFlight;
98
+ };
99
+
100
+ export const __resetFileTokenRecoveryForTests = (): void => {
101
+ recoveryInFlight = null;
102
+ lastRecoveryAt = 0;
103
+ };
@@ -0,0 +1,80 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { loadSecureStore } from './secureStoreRuntime';
3
+ import { pushLog } from '../utils/devLogger';
4
+
5
+ // Fallback keys are prefixed and namespaced away from every other
6
+ // AsyncStorage key this SDK writes, so a host that never installs
7
+ // expo-secure-store can still be told apart from one that used to lack
8
+ // it and has since added it (see `secureSet`'s stale-fallback cleanup).
9
+ const FALLBACK_PREFIX = '@ethora/secure-fallback:';
10
+
11
+ let warnedFallback = false;
12
+ const warnFallbackOnce = () => {
13
+ if (warnedFallback) {return;}
14
+ warnedFallback = true;
15
+ pushLog(
16
+ 'warn',
17
+ 'expo-secure-store is not installed — auth tokens, the XMPP ' +
18
+ 'password, and the message-history cipher key are falling back ' +
19
+ 'to plain AsyncStorage instead of the platform Keychain/Keystore. ' +
20
+ 'Add the optional peer dependency `expo-secure-store` to your app ' +
21
+ 'to store them securely.'
22
+ );
23
+ };
24
+
25
+ /**
26
+ * Small-value secure KV store: platform Keychain/Keystore via
27
+ * expo-secure-store when the host has it installed, plain (but still
28
+ * namespaced) AsyncStorage otherwise. NOT for bulk data — see
29
+ * `persistCrypto.ts`'s size note on why message history goes through
30
+ * AES instead of straight into this store.
31
+ */
32
+ export async function secureGet(key: string): Promise<string | null> {
33
+ const store = loadSecureStore();
34
+ if (store) {
35
+ try {
36
+ return await store.getItemAsync(key);
37
+ } catch (e) {
38
+ pushLog('warn', `secureStore: getItemAsync(${key}) failed`, e);
39
+ return null;
40
+ }
41
+ }
42
+ warnFallbackOnce();
43
+ return AsyncStorage.getItem(FALLBACK_PREFIX + key);
44
+ }
45
+
46
+ export async function secureSet(key: string, value: string): Promise<void> {
47
+ const store = loadSecureStore();
48
+ if (store) {
49
+ try {
50
+ await store.setItemAsync(key, value);
51
+ // Clean up a stale plaintext fallback copy from before this host
52
+ // added expo-secure-store — otherwise it sits on disk forever.
53
+ AsyncStorage.removeItem(FALLBACK_PREFIX + key).catch(() => undefined);
54
+ return;
55
+ } catch (e) {
56
+ pushLog('warn', `secureStore: setItemAsync(${key}) failed`, e);
57
+ return;
58
+ }
59
+ }
60
+ warnFallbackOnce();
61
+ await AsyncStorage.setItem(FALLBACK_PREFIX + key, value);
62
+ }
63
+
64
+ export async function secureRemove(key: string): Promise<void> {
65
+ const store = loadSecureStore();
66
+ if (store) {
67
+ try {
68
+ await store.deleteItemAsync(key);
69
+ } catch {
70
+ // Key may simply not exist — deleteItemAsync throwing here isn't
71
+ // actionable either way.
72
+ }
73
+ }
74
+ await AsyncStorage.removeItem(FALLBACK_PREFIX + key).catch(() => undefined);
75
+ }
76
+
77
+ /** Test seam only. */
78
+ export const __resetSecureKeyValueWarningForTests = (): void => {
79
+ warnedFallback = false;
80
+ };