Proper documentation of base protocols / handshake
Doxygen compatible documentation (?) at least for UI exposed library functions
MacOS build
Ideal project-wide goals before full-release:
Ncurses client
CLI/API client for integration with AI bots/etc (Julia)
Google PlayStore listing
FDroid listing (official repo, not ours)
Packaging for most major Linux/BSD distributions (official or otherwise)
iOS support
For public discussion (Library):
Peer struct is currently an array of struct; there may be benefits to moving it to a linked list, facilitating more of an OOP approach, though an incredible amount work would be involved.
Putting in a "wrong" password could be made impossible. We could accept any password and just create a new config file. When unlocking, we could try the hashed password (decryption_key) against all config files.
Git submodules vs ExternalProjects_Add vs other?
Seperate "keys" and "settings" databases? Currently a bad setting can crash the application (such as a bunk sticker). UI developers should work to prevent this, rather than working around the problem in a brutal fashion such as by encouraging users to delete their settings database. (which would be very hard on mobile). If implementing, remember to implement in change_password.
Use timezone info to determine default torrc? (Briar does this. This could really be a UI thing, though we do have the censored_region variable in lib). Timezone + language would be more effective.
File transfers: fallocate(linux)/lseek(linux) or pre-allocate files in some sort of null state. Would have to do this in OS specific manners https://devblogs.microsoft.com/oldnewthing/20160714-00/?p=93875
Could allow protocols to require an acknowledgement (ACK) of receipt by sending a fnv1a unsalted hash (uint32) back. Using a 64 byte checksum is unnecessary and wastes RAM space in the message struc, HOWEVER a truncated SHA3 may be better because it would be able to handle larger message sizes, because it doesn't rely on loading the entire message into stack... but we could easily re-write the fnv1a hasher function to use the heap. Either method does not require both sides to keep a shared index number of any type. Would need to store hashes for sent messages of this type in struct so that confirmation could rapidly be determined without having to re-hash every such message. Alternatively, we could just use time:nstime or time:nstime + hash.
For public discussion (UI Clients):
Be able to drag messages / completed files to other peers? Accidents could occur. Another option is "Forward to".
Keyboard Privacy in Flutter being enabled by default: it breaks non-alphabetical languages such as Chinese
TODO List for TorX Library:
High Priority / Security Audit:
Rewrite anywhere that we pass n+i to pass n+struct instead. Array of struct works fine for everything except messages.
Messages should be a linked list, then there is no realloc being called when loading and deleting messages, making deletion of stream messages low-cost.
UI message will have to register its' location with a void pointer to the library message, and library message will have to have a callback trigger to tell UI to delete the UI message before deleting itself.
Printing messages by linked list should be possible because we already do it in groups.
To consider: use reference counter on group stream messages and delete when too old or all sent.
Every library function should do basic sanity checks (ex: n > -1 && n < threadsafe_read_int(&mutex_global_variable,&max_peer), g > -1 && g < threadsafe_read_int(&mutex_global_variable,&max_group), etc), either with -1 or 0 error level, as appropriate. Diagnosing a -1 shutdown is far easier than a segfault on Android.
ENUM_PROTOCOL_FILE_INFO_REQUEST maybe should not be facilitated in public groups.
Certain types of group streams (A/V call data, for example) need only be sent to a subset of group peers.
Pointer objects are not properly accessible through getter_array and will fail getter_array_sanity_check and getter_group_array_sanity_check, with the exception of message. We will need to implement null checks and strlen.
offer/request_list is not accessible through getter/setter functions. If we don't rapidly remedy this, we will inconvenience future UI devs.
Some file related protocols are saved even if logging is disabled. This should be resolved.
message_resend hasn't been tested in a while. Test with public groups, private groups(signed), p2p.
Restarting Tor calls sql_populate_peer again. Much of it may be unnecessary if(messages_loaded). load_onion(n) and peer_init or whatever does tor calls may be necessary. More importantly, we should probably find a way to take down onions before shutting down Tor. If we did that, we could eliminate issues.
GROUP_OFFER_ACCEPT: ONLY respond IF we verify that we already sent this peer an UNUSED invitation (perhaps we should save this with extraneous), otherwise could be issues (ie, a malicious peer could accept multiple times and bring in a bunch of people)
iOS (Orbot) / System Tor: We need to re-write tor_call so that all calls are on a single connection and ADD_ONION does not utilize "Detached". See Tor's control-spec.txt. That will enable us to run safely without control_password. However it will not achieve Orbot compatibility at least on Android (which starts up with a random CTRL_PORT). We could work with their devs to get them to resolve the issue.
Tor not dying keeps onions online after crash. Consider the viability of a Tor Killer process that will kill Tor if TorX's PID dies. It could just be a wait() kill() process, being forked from TorX with possession of both Tor and TorX PIDs. This would be useful to ensure that Tor and its hidden services aren't left hanging if TorX crashes or is improperly closed. NOTE: probably better to use just not use detached? Next startup would kill tor via PID.
Consider the viability of (or move towards) full-duplex messages of all types, and treating files nearly the same as any other message.
Every message would need to have a checksum (for matching) and a start point, similar to how we do files now.
File transfer checksums fail after combination of sender crashes, stickers, messages, multi-file transfers, etc. Need audit.
Callback for invalid or incomplete message (which could be illict attempts to ping or do traffic analysis).
Minor notice for incomplete, major for invalid + counter.
Warning: After a file is cancelled, a peer can keep sending data or re-start sending data and we receive/disgard it. This could be exploited to monitor a peer.
Need to somehow notify a peer that such packets are still inbound.
Issue: Incomplete messages come in frequently in normal operation (faster than a monitor's framerate)
Issue: Invalid messages could come *incredibly* infrequently, if a malicious peer (ie, a peer could report a 1000 GB message and send it over weeks, never triggering an 'invalid' warning).
Thought: Invalid messages already report errors, so do we *really* need redundant callback, which has very little legitimate value?
Arti / Vanguards
Need to migrate to Arti as soon as viable and enable full vanguard support https://spec.torproject.org/vanguards-spec/full-vanguards.html
Alternative mitigation method offering full-vanguards (Note: abandonware) https://github.com/mikeperry-tor/vanguards
Tor >= 0.4.7.0 already has built-in support for Vanguards-lite: https://spec.torproject.org/vanguards-spec/vanguards-lite.html
Need a red team building malicious or buggy client/library, which will send undersized/oversized messages, spam attacks, etc.
Medium Priority:
(Easy fix) In sql_populate_message, if(reverse) and if(protocol == ENUM_PROTOCOL_FILE_REQUEST), we should probably avoid "status = " changes to _ACCEPTED.
(Easy fix) Implement a "min_fail" to reduce the cost of begin_cascade and peer_offline. It should initialize at 0, be increased to max_i by begin_cascade, and be reduced to min_i by load_more. It should only be utilized by begin_cascade and perhaps peer_offline. Alternative: pass i of last sent message to begin_cascade, but that won't account for load_more, which may or may not be desirable. Simpler though. NO ---> Implement an `int* queue` in peer struct. Add 'i' to it when "Refusing to send_prep" and "Send_prep too early" in send_prep, and when `].stat = ` in load_messages_struc. Read from queue to determine next message to send, in begin_cascade. Remove from queue in packet_removal and when message is deleted (Note: may not be necessary when deleted). Note: This is 'low priority' because show_log_messages limits the amount of messages required to be parsed without a queue. NOTE: Could result in rare double-sends due to race between begin_cascade and packet_removal? Our current setup is subject to the same potential race? Presumably yes on socket_swappable messages, since ENUM_MESSAGE_SENT is set in packet_removal. Both sockets *could* hypothetically send the same message. Solution is to "claim" it somehow? Minor problem, solve later as seperate TODO.
2025/04/13 Flutter: "Cannot open file path /data/user/0/com.torx.chat/cache/file_picker/1744539315957/新建文本文档 (2).txt for sending. Check permissions.". Caused by a file being shared from "Recent", then (an hour or two later) accepted by peer. Temporary solution (and good idea): Peer will naturally re-send file with same hash after this bug. When receiving a file offer for a file we already have and have already made a request for (presumably which is stalled), re-request it.
ENUM_PROTOCOL_FILE_REQUEST is logged so that we can set the status of the file. This is a lot of bloat, considering that one file could have many requests, especially in groups. It would be more efficient (disk space) to store the file status in another manner.
Group file transfers of 4 byte files fail in file_init: "Coding or IO error. File size != sum of sections" 4!=8. More testing and diagnosis required.
"Last transferred > transferred" occurs frequently (on the sender side only?) when starting file transfers.
Blacklisting should only occur if you requested the whole section from a single peer, otherwise we have no idea who we got the bad packet from. We currently have no way of tracking this because we only track split_status_req. We will have to track split_status_req_start and split_status_req_end.
Zero_ functions should have UI callbacks. There are limitations related to locks regarding how we could implement this. Remember to put them outside the function (after is preferable, but before is fine during shutdown).
Group File Transfers:
Important: select_peer should probably return a list of peers, or at least a fd_type and the proposed section.
select_peer seems to select the original offerer of a file most of the time, rather than utilizing those who sent FILE_OFFER_PARTIAL data.
We rely on section_update to request the next section when one section is complete, but what if we requested less than a full section from a peer? ie: if we requested from a _PARTIAL? Until we resolve this, we should perhaps avoid requesting partial sections.
Need a ENUM_PROTOCOL_FILE_REFUSE protocol so that, for example, if a peer has moved/deleted a file or changed its permissions, the requesting peer doesn't wait endlessly for data to arrive after making a request. Note: Can simply send a _PARTIAL with 0/0/0 and have the receiver cancel any requests from this peer.
CMakeLists.txt:
Needs to have install directive (LIBRARY DESTINATION lib), to allow independent builds and installs of .so file, without re-compiling UIs.
set(SSL_ARCH linux-x86_64) is hardcoded, except on android. will be issues on *pi, postmarketOS, macbooks, etc.
CMakeLists.txt files can be ran through AI. Add debug messages with message(STATUS hello) and run with cmake --trace for debugging.
Prioritize our own broadcasts: Calling broadcast_add(-1,...), to add a group, could take a very long time because manually added groups are not prioritized in broadcast_threaded. Should probably have an additional queue of high priority (our own) broadcasts.
Due to message_prep existing within message_send, and only one g being passed around (no distinction between "relevant g" and "target g"), it's impossible to send a group offer into a group.
Search (again) for ]; and ] = { then ensure zero'd.
Streaming a group message is going to be a message struct bloat issue because, unlike other stream messages, upon outbound send it is not deleted from group_ctrl (the group_ctrl n,i is not zero_i'd). The solution is to somehow track when all the attempts are done (perhaps in message_send) and then zero_i it (see: sfaoij2309fjfw). We may also need to have a time-deletion where after a certain number of seconds we just consider it no longer relevant.
Multi-Device / Blinded keys. Use the nonce method to generate blinded keys. Do it using onion_gen.c Upload it using HSPOST. See src/feature/hs/hs_common.c for creation of blinded keys. See any mentions of "blind" "period" "time" in the src. I think HSPOST is somehow combined with ADD_ONION to publish? Unsure and will need to ask #tor-dev
GROUP FILE TRANSFER Documentation: Outbound uses peer_n fd for disk reads, Inbound uses group_ctrl fd for disk writes. When receiving file request, it appears we store outbound date in the group_peer_n. This needs to be documented/understood. When changing file status in process_pause_cancel, we might need to iterate through the relevant group_peer_n and set their status too? idk if we store status there or only transfer amount.
We can't support uint64_t file sizes because ftell/fseek only support long int. Unsure what to do about this. It affects our file transfer protocols.
accept_automatically. Can either be a toggle or a size slider. size_t is probably most logical. Could also have a list of accepted filetypes. NOTE: Enabling this option will require a check for download_dir. Also, this option should could be DANGEROUS for insecure platforms like Windows/OSX/iOS/Android, where CSAM scanning exists.
If a split_folder exists, files inside should be labelled via truncated checksum rather than filename.
file_set_path should be able to move a file, if existing and destination is writable.
Hash is written to disk in plaintext for our .split file. Perhaps we should encrypt (no) or salt + rehash it (not all hashes, just this hash written to .split file). The reason we don't is because the file itself is written next to it, so what is the security in having the hash salted? We do attempt to securely delete .split files.
Sodium memory management overhead: Check for compile-time flags that could disable the wasted pages except on debug builds. sodium_malloc() wastes too much memory by allocating 4kb of space for each malloc. See HAVE_PAGE_PROTECTION
Clean up error messages / notices / checkpoints using macro defined levels to determine whether debug level + whether they contain sensitive info.
Error messages cannot be inside torx_read/torx_write in case callbacks are guaranteed to be handled asyncronously, by adding them to a queue. Currently, very few are, if any.
2025/04/29: After dozens or hundreds of disconnections occuring rapidly, we get "ERROR MEMORY sqlcipher_mlock: mlock() returned -1 errno=12". This is possibly from too many sodium_malloc not being free'd when disconnecting?
Low Priority:
A "getter_exists" function could exist, which would at minimum be used for pointers to see if they are NULL. Could error out if not a pointer, or do some other form of checks like a zero check on the first byte (for onions, peeronions) or is_null (for hashes, other arrays).
Change 'n' to 'file_n' in file related functions that are passed n,f pairs or n,f,peer_n. n and file_n must NEVER be used together in a function, to prevent confusion/mistakes. Relevant variable names: file_n, target_n, group_n, peer_n, etc.
If messages.db is deleted or message history is deleted, _ENTRY_REQUEST _FAIL messages will be deleted, which means public groups we are trying to join will never be joined.
2025/01/15: Pausing is near indistinguishable from simply being inactive (ENUM_FILE_INACTIVE_ACCEPTED). As long as file_path is set, we treat it as accepted, and then any incoming offer will start the transfer. This inability to permanently pause (without cancelling) is annoying, but we never had a strong pause because either peer could unpause. Therefore, this is OK. Do not abolish pause protocol. It serves other purposes.
We have some places where we unnecessarily fwrite multiple times in sequence rather than once, such as in initialize_split_info.
Investigate changing build system to Meson and using Git submodules, as suggested in Issue #2.
Don't send a ENUM_PROTOCOL_FILE_OFFER_PARTIAL to the peer we received the data from. (Actually, maybe this shouldn't be done).
PROPOSE_UPGRADE:
After acting on a PROPOSE_UPGRADE, a restart is required before v3auth will be implemented. This can be resolved.
Currently we PROPOSE_UPGRADE on every connection. We can avoid that if we store the current value of the connection and not just peerversion.
There are a few places we can be more careful about not de-referencing null pointers. Search blake3.c and base32.c for " *" (aka \t*). The blake3 functions do no sanity checks on arguments passed, and the base32_decode function can be to be re-written (in stack).
"Include the system error text (from perror or equivalent) in every error message resulting from a failing system call" https://www.gnu.org/prep/standards/html_node/Semantics.html
Onloading/offloading old messages:
Offloading: Should leave us with just -10 to 10 initialized, on all peers
delete_log should probably be broken up into log_delete and shrink_message_struct, where log_delete calls shrink_message_struct, but shrink_message_struct can be separately called. Both could take n (or -1) as args.
Cache Solution Proposal #1 (bad)
When offloaded, we cache on the initialized message struct, then when re-loading, we just move to a temp local pointer, then sql_populate_message, then add back the cached messages via load_message_struc
Cache Solution Proposal #2 (better)
We offload all messages, except the 10 most recent, which we move to 0 to 10.
If we keep the ~50 most recent instead of 10, we can just rely on load_more later.
Remaining issue: We can't just offload all except a set number because then group_peer messages won't align with the appropriate group_n messages.
Add a `message_spoof(n,time,nstime,data,len)` function where users can click between messages to add a fake message to their history. Primary Issue: How we fit this into the message struct? This is where a linked list struct would be handy. Secondary issue: Is there significant value? The order in which it is inserted into SQLCipher might give it away as non-genuine.
Multiple offers of the same file with different filenames to the same peer has some weird behavior but is safe.
Documentation: As of 2.0.10, PIPE_AUTH is signed and utilized when v3auth is not available (Tor <0.4.6.1) to facilitate secure full-duplex connections.
Documentation: PROPOSE_UPGRADE works for upgrades from v1 (PIPE_AUTH) to v2 (v3auth), but cannot facilitate downgrades (and for many reasons should/will never). However, if both peers upgrade then disable v3auth, it will successfully fall back to PIPE_AUTH.
Where multiple getter functions occur in a block, it would be more efficient to manually lock/unlock once.
Consider implementation of Proof of Work https://spec.torproject.org/hspow-spec/v1-equix.html for multiple use IDs, when sufficiently mature
Convert or eliminate remaining ~100 printf to error_printf
Takedown_onion must call disconnect_forever in a threadsafe manner. We've tried everything (evbuffer_lock, event_base_once, etc) and can't find a way.
file_init() calculates a checksum every time it offers a file. We have modification time now but we don't use it for anything.
Seems like old file descriptors get closed. If nothing is written in a long time, fd might get closed. Do we have any long-term fd?
File descriptor leaks and limitations: ulimit -n shows we can only have 1024 file descriptors open at once. That's going to limit the potential of group chats. If we get near the limit, we could shed outbound (sendfd) connections? Not a great solution.
Lots of warnings occur when restarting Tor.
Cascade deletion of messages and peer specific settings may be untested
We don't have library protection against running twice. We implement "running" check in GTK. For now, this is ideal. No reason to change this.
Is --keygen/--key-expiration only for relays? OfflineMasterKey/SigningKeyLifetime
man atexit. May be useful. Note: Doesn't trigger on signals (ie ctrl + c). Not sure why this would be useful since we handle all exit() calls.
Add a counter or bunch of counters that increment every time a malloc occurs, so we can know how many leaks we got. (optionally in what areas)
Public Groups could hypothetically also be shortened in length (pointless), or allow external generation (pointless)
Consider having UTF8 validator shift forward over any non-utf8 bytes, for use in libevent.c and perhaps message_send (to avoid sql issues), rather than discarding whole messages.
For GROUP_PEER, .message and .message_len could be double pointer + pointer, respectively. Unsure if viable and how we would re-structure our message struct for that. This can be ignored for now so long as we aren't having bugs.
Consider ripping out libsodium and replacing it with with openssl (since it is already a tor dependency) or libressl. Be sure that we can do everything in onion_gen.c (ex: crypto_sign_ed25519_pk_to_curve25519)
Consider moving the message size and protocol behind the .message pointer (so we can avoid copying moving message when signing).
Main issue is that then freeing messages would require a special torx_free, which is very bad. Not worth it.
Kill codes have never been tested in groups because deleting individual peers in groups is a complex concept (since they'll just be re-added)
TODO List for Both UIs (Flutter and GTK4):
High Priority / Security Audit:
peer_onine_cb/peer_offline_cb/call_peer_joining/call_peer_leaving should trigger rebuilds of popovers. In GTK, by re-populating the appropriate list_store. In Flutter, with changeNotifierPopoverList.
Participating List popover should also be re-built when a peer is speaking (to flash badge), and in GTK when someone clicks "mic/mic_off" "volume_up/volume_off" icons to toggle peer specific setting in Participant List (currently it is static).
Pete Hegseth function: When a new GROUP_PEER joins, some sort of message needs to be displayed in channel showing who invited them. Perhaps we should generate a non-sendable message type that can be saved into the database and appear as a permanent local notification in the channel.
Missed call: should also be displayed as a non-sendable message in channel, similar to Pete Hegseth function. Completed calls probably don't need to be noted.
RAM: Get stickers out of RAM.
Un-pause option is not available for PM transfers. (May also apply to Flutter?)
Messages that come in out-of-order in group chats are printed as the come in, instead of in-order, if chat is open. (May also apply to Flutter?)
When deleting group chat history, only sent public messages disappear immediately. The rest disappear when the chat route is re-opened. (Possibly related to above) (May also apply to Flutter?)
Global and per-peer settings of "Enable microphone"
Check destination folder write permissions before allowing its' selection
String functions in UI should use secure allocators/de-allocators, if possible. (Note: not possible?)
Analyze audio recordings for metadata? Requires writing samples to disk or analyzing sources https://gstreamer.freedesktop.org/documentation/application-development/advanced/metadata.html?gi-language=c
Medium Priority:
RAM: Perhaps offload messages as soon as we get to the bottom?
Streaming audio: Ideas? The biggest issue is playback. In audio.c, we would have to write a new playback function. In flutter, unknown.
Walkie-talkie mode / Touch to speak: When enabled during a voice call, display Participant List and only two buttons: one small one to leave the mode, and a massive one to touch to speak. Touching simply enables microphone, which is otherwise disabled.
There could be an UI option to set a debug_file location, and then upon startup have that log pop up (partially as a reminder that it should be disabled).
Better notifications for calls
Clicking notifications (both message and calls) should open the proper route (Flutter + GTK)
Flutter notifications should cancel after replies are sent (attempts made, no success)
Accept / Decline within the notification (GTK)
Peer list should rebuild and display something, or flash, to indicate an waiting call (Flutter + GTK)
Notifications may need to last longer (Flutter + GTK)
Test and document "Stealth addresses". Facilitated by peer_save(), "Stealth Addresses" functionality is where invalid (non-base32) and excessive (beyond 51 characters) characters are stripped. To utilize, take a 51(?) length TorX-ID, sprinkle invalid characters throughout it as desired, add unlimited length suffix trailing it, and then pass to peer_save. Note: cannot be exactly 56 characters long? Needs review and testing.
Have a toggle for kill_delete. Delete or Disable options.
Facilitate msg searching via gtk_list_view_scroll_to in GTK4 and ?? in Flutter.
message_load_more could take a specific time nstime as argument, or time/nstime AND _MIN/_MAX to designate loading more forwards/backwards from a specific message. These would have to be passed to sql_populate_message. This could facilitate loading of searched messages and then scroll from there. NOTE: This will only *really* save having to load thousands of messages if the user then doesn't scroll afterwards and clicks back or something.
We need to do sanity checks on sticker/image data or people can be crashed with junk stickers/images. (Send 0 size .gif or bunk data for testing)
Flash entry box red when no nick is entered for generating (generate_onion) or adding onion (save_peer), or when an invalid onion is passed (bad checksum)
Consider registering a URI? ie: "torx:" Base64 would be a grup, base32 would be a SING/MULT. is_valid_b32_input( and b64_isvalidchar( in conjunction can determine whether a string is peer/group/trash, for use with 'Search' or invalid input when adding peer.
Low Priority:
"Tor is running on port ..." could be displayed on settings page or "Tor Port: ..." at the top of Tor Log? (better)
"Peer Group Block" lists could be replaced with "Person Groups(or Diversity_2) No_Accounts" Google SVG icons for more standardized and intuitive appearance
If a last_message is too long, is there any way we can prevent it from cutting a character in half? We can't simply use multiples of 4 because spaces and newlines.
Multi-select messages and "forward" / "delete" / "resend" for them
ENUM_PROTOCOL_UTF8_TEXT_QUOTE could include a suffix of the quoted message time + nstime. Main difficulty in implementation is UI design.
Multi-Select: Tables should allow multiple selections for deletion. It should show only Delete (or Accept + Reject).
Implement our fancy new .SVG icons (can wait for GTK4.14) and colorize, replacing .PNG files. Search our code for gtk_symbolic_paintable_snapshot_symbolic, where we have an example implementation ready.
Tooltips: Use text_tooltip_ prefix. For flutter, https://material.io/components/tooltips alternatively we have used showSnackBar in Flutter and could use it for safety warnings/etc.
Have a tooltip that shows TorX-IDs, at least on the group's peerlist
If someone is fast on the censored region toggle while waiting for login, it will save the setting but not take effect until next restart
Should probably have a "doing checksum" spinner or something for file transfers, so people don't add more than once
Could have a toggleable option about whether to run as a tor binary as a middle node (this would support the network, but be bandwidth eating)
TODO List for GTK4 client:
High Priority / Security Audit:
transfer_progress_idle can segfault on t_peer[n].t_file[f].progress_bar if messages are deleted. We should be nulling t_peer[n].t_file[f].progress_bar when deleting file messages.
Clearing group messages only makes the outbound group messages immediately disappear and doesn't effect the GROUP_PEER messages.
Need to list appropriate GStreamer package as a build dependancy
t_main.global_pos and ].pos need to be analysed. Whether they are fully working or not is unknown. It's likely that adding messages from pos==0 is breaking every subsequent .pos, which likely needs to be modified (so, if we add 15 messages from 0, every other message with >0 ].pos needs to be +=15. For efficiency, this would be done in the functions that call print_message, not in print_message itself).
ListView should be a direct child of ScrolledWindow. If it is a child of a box, there may be issues if having >205 widgets (experienced in a test build). There are 3 places where we might face this issue (ctrl+f gtk_list_view_new), but our chat history itself is properly setup.
Medium Priority:
file_set_path should be used to set .file_path, instead of manually setting it.
GTK_FACTORY_BUG mitigation has a side effect: messages are not reloaded until application restart, which means that modifying peernicks of group members do not change nicks within loaded messages until restart. Mitigate by re-loading effected messages.
Bug: Messages that are larger than the chat window cannot be long-pressed properly (so cannot copy, etc). Issue is caused by the popover being spawned at the top of the message rather than the point of long-press.
While minimized to tray, message scroll doesn't really work. The scroll_func_idle gets called, but to no effect.
Create .deb file + Debian repo
Create .rpm file + RedHat repo
Create .??? file + MacOS brew.sh repo
Windows build:
Saving torrc results in warnings to override. Should complain to #tor if they persist.
Need to ship an installer or just zip up the files (if that is sufficient).
Need a "Microsoft code signing certificate"(?) to be able to distribute without warnings.
"Microsoft Store" listing should be considered.
Note for devs: torx-tray.exe may not die when TorX is abruptly killed (ex: ctrl+c in GDB) because TCP connections are not properly closed. Unavoidable without dropping a PID file, but this should only be an issue for devs who are repeatedly building in the same directory of execution (builds might fail on torx-tray.exe because it is running). This issue should not exist for users because multiple instances of torx-tray.exe can run concurrently.
Images should be clickable (to show larger).
Low Priority:
Landscape style images, at least in group PM, end up displaying undersized in an oversized message bubble.
Allow adding multiple stickers at once, from filepicker.
Rebuild message list after file transfer deletes (or specific message)
Clicking back while modifying peernick causes loss of changes (only in GTK4)
Vertical mode: consider putting Send button below the emoji and attach buttons, or simply hide buttons other than Send while typing (like Flutter client).
Memory leakage: Free memory. Eliminate memory leaks so that it can valgrind 0. g_free, g_object_free(), etc Unsure how to handle sensitive things.
Review any _swapped( and instead set proper args for given ::signal) (note: if signal can't be found in GTK docs, check gobject docs)
Have some clang specific compile flags. Could add more. See CMakeLists.txt.
Fully Mitigated by GTK_FACTORY_BUG=1: g_list_store_insert/splice in GTK4 are horribly inefficient until https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/7420 gets merged
Partially mitigated by GTK_FACTORY_BUG=1: Loading chats is horribly slow until gtk_list_base_set_anchor_max_widgets stops being passed GTK_LIST_VIEW_MAX_LIST_ITEMS as n_center, because it builds 205 widgets.
INVERSION_TEST is necessary until https://gitlab.gnome.org/GNOME/gtk/-/issues/4680 gets resolved
Gnotification can't use gresource icon. We already worked around it by dropping a .png, but we also have a .png for our .desktop file. If we set icon_logo to NULL, the icon registered with DBUS by .desktop will be used.
TODO List for Flutter client:
High Priority / Security Audit:
Outgoing voice messages are momentarily cached on disk: record.start( needs replacing with record.startStream(, but currently the "record" package has bugs
Values passed to changeNotifier(s) are inconsistent and arbitrary because in most cases we don't use them. We should universally standardize them and utilize them with $changeNotifier.section.$value
CMakeLists.txt: Depreciate the BUILD_BINARIES argument in favor of checking if they are already built.
Passing environmental variables to CMake through Flutter seems unreliable at best (may only be working when building re-binaries, with clean directories, at best).
Resolve issues / causes of unnecessary rebuilds (libevent related issue). Alternatively, BUILD_ALWAYS TRUE or otherwise force clean rebuild of libevent.
Allow forcing of rebuilds for when deps change? CMake can ideally handle this
CMakeLists.txt: Ship a release version of Tor instead of building from main (this requires following tor-announce mailing list and manually updating CMakeLists.txt for every stable release)
File picker caches in /data/user/0/com.torx.chat/cache/file_picker/, causing failure to resume outbound transfers after restarting
Can we prevent other applications from knowing this application is installed?
Client attempts to connect to https://firebaselogging.googleapis.com/v0cc/log/batch?format=json_proto3. Need to prevent that and verify that it isn't making other connections. We may need to fork all our dependencies to disable any firebase reference or remote connections.
Consider having a popup when adding something to clipboard. The clipboard would have a "Clear clipboard" and "Exit" option, along with a warning about other applications being able to steal clipboard contents. In some softwares (ie password managers), after ~45 seconds, it will clear the clipboard.
Medium Priority:
Need to do more testing with horizontal views. Known issue: Deleting stuff on Home page is impossible in horizontal mode. Other stuff untested.
Rebuilds are still too frequent; mostly when bringing keyboard up, NOT caused by use of MediaQuery (tested by eliminating all). https://github.com/flutter/flutter/issues/105184
Crash: Likely related to but NOT caused by android:stopWithTask="false" in AndroidManifest.xml? Read: https://stackoverflow.com/questions/19568315/how-to-handle-running-service-when-app-is-killed-by-swiping-in-android Occurs occassionally when application is in the background, especially when other high-RAM applications are running https://stackoverflow.com/questions/44425584/context-startforegroundservice-did-not-then-call-service-startforeground E/AndroidRuntime(12140): android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{52682ad u0 com.torx.chat/com.dexterous.flutterlocalnotifications.ForegroundService}
Crash: Also FlutterLocalNotifications, Unable to start service com.dexterous.flutterlocalnotifications.ForegroundService@52b4439 with null: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.Serializable android.content.Intent.getSerializableExtra(java.lang.String, java.lang.Class)' on a null object reference
Isolates: showsUserInterface should be false, but we can't get it to work. Seems like few if any have (seems like they only use it with cancelNotification): https://github.com/search?q=%22showsUserInterface%3A+false%22&type=code with the only exception being here: https://github.com/jenspfahl/EverydayTasks/blob/a85475deae37649ba8ef18978e19270e3ba7ebb6/lib/ui/pages/ScheduledTaskList.dart#L977 Note: If we re-write our notifications (and perhaps callbacks) in native code for better lifecycle management, this issue would be irrelevant.
Delete temporaryDir/qr.png on program startup and shutdown (or when going to AppLifecycleState.paused?). Zero and delete might be best.
Message box height: 400 is too tall. Figure out a way to avoid hard coding it.
Low Priority:
Too long of a nick can overflow a activity bar.
Consider other default ringtone/beeps, such as https://freesound.org/people/knufds/sounds/633159/
"Resend" is available in different/less circumstances than in GTK
Flutter CMakeLists.txt: If jnilibs is populated with files, don't try to copy output binaries into jnilibs because if deleted the build dir and rebuilt a release only, it will be empty.
Can't change app name on the fly, but can change icon. Could use it to notify user of messages or put alternate icon option (calculator, or something people never use). "The calculator theoretically opens chat but it doesn't work anymore. They said it requires entering a specific calculation," Micay said.
Should use gallery with photo_view to allow swipping back/forward to see other images in PhotoView.
autoRunOnBoot: true (foreground task) + fix BootBroadcastReceiver.kt, then have a toggle in settings page for both.
Calling peer_accept() while actively modifying peernick results in modifications being lost
Lifecycle: Notifications may have to handled by callbacks written in Java/Kotlin to prevent their disposal during lifecycle events. Singleton was attempted, but didn't help.
Lifecycle: RestorationScopeId seems to not be saving our route. Unsure if it saves anything. If we can get it to work, we can use restorationId on TextField and ScrollView (note: security implications of saving to disk in cleartext)
Lifecycle needs a full audit, including use of restorationScopeId, initialization_functions(), resumptionTasks()
Prevent un-encrypted backups of android data? Most chat apps do this but I'm on the fence because our data is encrypted, and we do want to support history migration. GrapheneOS project has some info that suggests we can block only unencrypted backups.
Comment out any unused color and language strings. Ensure that we don't have any strings not in our languages file.
AnimatedBuilder should replace most or all remaining of our setState calls, for efficiency. There are few left.
We lose TorX log and Tor log contents every time we .detach, so we might consider to store it in a library defined C pointer so it stays in RAM. We would just need to create the pointer in lib and the remaining work is done in flutter. However, this is kind of contrary to the direction we are going, which is to be able to minimize RAM usage in Android.