diff --git a/app/providers/SystemAccountsProvider/SystemAccountsProvider.tsx b/app/providers/SystemAccountsProvider/SystemAccountsProvider.tsx index 9166882..9e14da3 100644 --- a/app/providers/SystemAccountsProvider/SystemAccountsProvider.tsx +++ b/app/providers/SystemAccountsProvider/SystemAccountsProvider.tsx @@ -1,9 +1,8 @@ import { useDatabase } from "@/app/providers/DatabaseProvider/useDatabase"; -import { createContext, useEffect } from "react"; +import { createContext } from "react"; import { useSystemAccount } from "./useSystemAccount"; import { usePublicKey } from "../AccountProvider/usePublicKey"; import { usePrivatePlain } from "../AccountProvider/usePrivatePlain"; -import { APP_VERSION, RELEASE_NOTICE } from "@/app/version"; import { chacha20Encrypt, encodeWithPassword, encrypt } from "@/app/crypto/crypto"; import { generateRandomKey } from "@/app/utils/utils"; import { DeliveredMessageState } from "../DialogProvider/DialogProvider"; @@ -11,7 +10,11 @@ import { UserInformation } from "../InformationProvider/InformationProvider"; import { useNotification } from "@/app/hooks/useNotification"; import { useDialogsList } from "../DialogListProvider/useDialogsList"; -export const SystemAccountContext = createContext(null); +export interface SystemAccountContextValue { + sendMessageFromSystemAccount: (accountUsername: string, message: string) => Promise; +} + +export const SystemAccountContext = createContext(null); export interface SystemUserInformation extends UserInformation { avatar: string; @@ -23,49 +26,37 @@ interface SystemAccountProviderProps { export function SystemAccountProvider(props : SystemAccountProviderProps) { const {runQuery} = useDatabase(); - const lastNoticeVersion = localStorage.getItem("lastNoticeVersion") || "0.0.0"; - const updateAccount = useSystemAccount("updates"); const publicKey = usePublicKey(); const privatePlain = usePrivatePlain(); const {updateDialog} = useDialogsList(); const notify = useNotification(); - useEffect(() => { - if(publicKey == ""){ - return; + const sendMessageFromSystemAccount = async (accountUsername: string, message: string) => { + const account = useSystemAccount(accountUsername); + if(!account){ + throw new Error("System account not found"); } - if(lastNoticeVersion !== APP_VERSION){ - sendReleaseNoticeFromUpdatesAccount(); - localStorage.setItem("lastNoticeVersion", APP_VERSION); - } - }, [lastNoticeVersion, publicKey]); - - const sendReleaseNoticeFromUpdatesAccount = async () => { - const message = RELEASE_NOTICE; - if(message.trim() == ""){ - return; - } - const cahchaEncrypted = await chacha20Encrypt(message.trim()); + const chachaEncrypted : any = await chacha20Encrypt(message.trim()); const key = Buffer.concat([ - Buffer.from(cahchaEncrypted.key, "hex"), - Buffer.from(cahchaEncrypted.nonce, "hex")]); + Buffer.from(chachaEncrypted.key, "hex"), + Buffer.from(chachaEncrypted.nonce, "hex")]); const encryptedKey = await encrypt(key.toString('binary'), publicKey); const messageId = generateRandomKey(16); const plainMessage = await encodeWithPassword(privatePlain, message.trim()); - - await runQuery(` INSERT INTO messages (from_public_key, to_public_key, content, timestamp, read, chacha_key, from_me, plain_message, account, message_id, delivered, attachments) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `, [updateAccount!.publicKey, publicKey, cahchaEncrypted.ciphertext, Date.now(), 0, encryptedKey, 0, plainMessage, publicKey, messageId, DeliveredMessageState.DELIVERED, JSON.stringify([])]); - updateDialog(updateAccount!.publicKey); + `, [account.publicKey, publicKey, chachaEncrypted.ciphertext, Date.now(), 0, encryptedKey, 0, plainMessage, publicKey, messageId, DeliveredMessageState.DELIVERED, JSON.stringify([])]); + updateDialog(account.publicKey); notify("New message", "You have a new message"); } return ( - + {props.children} ) diff --git a/app/providers/SystemAccountsProvider/avatars/safe.png b/app/providers/SystemAccountsProvider/avatars/safe.png new file mode 100644 index 0000000..a6a13b7 Binary files /dev/null and b/app/providers/SystemAccountsProvider/avatars/safe.png differ diff --git a/app/providers/SystemAccountsProvider/useSendSystemMessage.ts b/app/providers/SystemAccountsProvider/useSendSystemMessage.ts new file mode 100644 index 0000000..2da1dec --- /dev/null +++ b/app/providers/SystemAccountsProvider/useSendSystemMessage.ts @@ -0,0 +1,21 @@ +import { useContext } from "react"; +import { SystemAccountContext } from "./SystemAccountsProvider"; + +/** + * Возвращает функцию для отправки системного сообщения от имени указанного системного аккаунта + * + * ВАЖНО! Данный хук отправляет сообщение в текущий залогиненный аккаунт. + * @param accountUsername имя системного аккаунта от которого необходимо отправить сообщение + * @returns + */ +export function useSendSystemMessage(accountUsername : string) { + const context = useContext(SystemAccountContext); + if(!context){ + throw new Error("useSystemSend must be used within a SystemAccountProvider"); + } + const send = (message: string) => { + return context.sendMessageFromSystemAccount(accountUsername, message); + } + + return send; +} \ No newline at end of file diff --git a/app/providers/SystemAccountsProvider/useSystemAccounts.ts b/app/providers/SystemAccountsProvider/useSystemAccounts.ts index 80baa1d..a3aaa3e 100644 --- a/app/providers/SystemAccountsProvider/useSystemAccounts.ts +++ b/app/providers/SystemAccountsProvider/useSystemAccounts.ts @@ -1,6 +1,7 @@ import { OnlineState } from "@/app/providers/ProtocolProvider/protocol/packets/packet.onlinestate"; import { SystemUserInformation } from "./SystemAccountsProvider"; import updates from './avatars/updates.png'; +import safe from './avatars/safe.png'; export function useSystemAccounts() : SystemUserInformation[] { const accounts : SystemUserInformation[] = [ @@ -11,6 +12,14 @@ export function useSystemAccounts() : SystemUserInformation[] { username: "updates", online: OnlineState.OFFLINE, avatar: updates + }, + { + publicKey: "0x000000000000000000000000000000000000000002", + verified: 1, + title: "Safe", + username: "safe", + online: OnlineState.OFFLINE, + avatar: safe } ]; diff --git a/app/providers/SystemProvider/useSystemInformation.ts b/app/providers/SystemProvider/useSystemInformation.ts new file mode 100644 index 0000000..a1f32c7 --- /dev/null +++ b/app/providers/SystemProvider/useSystemInformation.ts @@ -0,0 +1,30 @@ +import { useContext } from "react"; +import { SystemProviderContext } from "./SystemProvider"; + +/** + * Информация о системе и устройстве + */ +export interface SystemInformation { + /** + * Уникальный обезличенный идентификатор устройства + */ + id: string; + /** + * Имя устройства + */ + name: string; + /** + * Операционная система устройства + */ + os: string; +} + +export function useSystemInformation() : SystemInformation { + const context = useContext(SystemProviderContext); + + if(!context) { + throw new Error("useSystemInformation must be used within a SystemProvider"); + } + + return context as SystemInformation; +} \ No newline at end of file diff --git a/app/views/Main/Main.tsx b/app/views/Main/Main.tsx index beea69d..cf9a7e6 100644 --- a/app/views/Main/Main.tsx +++ b/app/views/Main/Main.tsx @@ -27,13 +27,32 @@ import { useDatabase } from "@/app/providers/DatabaseProvider/useDatabase"; import { useMemoryClean } from "@/app/providers/MemoryProvider/useMemoryClean"; import { useAccountProvider } from "@/app/providers/AccountProvider/useAccountProvider"; import { useLogout } from "@/app/providers/AccountProvider/useLogout"; +import { useUpdateMessage } from "@/app/hooks/useUpdateMessage"; +import { useDeviceMessage } from "@/app/hooks/useDeviceMessage"; export function Main() { const { mainColor, borderColor } = useRosettaColors(); const { lg } = useRosettaBreakpoints(); const location = useLocation(); const [viewState, setViewState] = useViewPanelsState(); + + /** + * Слушаем диалоги в пассивном режиме + */ useDialogFiber(); + + /** + * Отправляем сообщение об обновлении, + * если версия приложения изменилась + */ + useUpdateMessage(); + + /** + * Слушаем все сообщения на присоединение новых устройств + * к нашему аккаунту + */ + useDeviceMessage(); + const { setSize, setResizeble } = useWindow(); /**