Compare commits

...

251 Commits

Author SHA1 Message Date
Sarah Jamie Lewis 055e1d65a1 Merge pull request 'Update 'README.md'' (#117) from sarah-patch-3 into trunk
continuous-integration/drone/push Build is pending Details
Reviewed-on: #117
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2023-06-16 21:07:15 +00:00
Sarah Jamie Lewis 8a7c647ea0 Update 'README.md'
continuous-integration/drone/pr Build is pending Details
2023-06-16 21:07:09 +00:00
Sarah Jamie Lewis 5871a2c077 Update 'README.md'
continuous-integration/drone/pr Build is pending Details
2023-06-16 21:05:32 +00:00
Sarah Jamie Lewis ae179fab72 Ensure Block Unknown Connections Settings is Respected on Protocol Engine Restart
continuous-integration/drone/pr Build is running Details
continuous-integration/drone/push Build is passing Details
2023-02-08 13:51:09 -08:00
Sarah Jamie Lewis dd411bd337 Update Android Container
continuous-integration/drone/pr Build is running Details
continuous-integration/drone/push Build is passing Details
2023-01-31 18:34:11 -08:00
Sarah Jamie Lewis 1d3d2878b7 Updating Android/GoMobile Docker
continuous-integration/drone/pr Build is running Details
continuous-integration/drone/push Build is passing Details
2023-01-26 08:51:10 -08:00
Sarah Jamie Lewis 28fe3b21fb Add trimpath, essential for Android repeatability
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-01-12 13:17:45 -08:00
Sarah Jamie Lewis 20897a9f8d grammar
continuous-integration/drone/pr Build is running Details
2023-01-12 11:21:10 -08:00
Sarah Jamie Lewis 709d377bf4 Remove timestamp from Windows DLLs
continuous-integration/drone/pr Build is running Details
2023-01-12 10:37:21 -08:00
Sarah Jamie Lewis 1baac147d7 Update Windows Docker ref
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is running Details
2023-01-11 13:15:06 -08:00
Sarah Jamie Lewis f152b02230 Build Ids for Android, Windows, and Mac Builds
continuous-integration/drone/pr Build is pending Details
2023-01-11 12:21:49 -08:00
Sarah Jamie Lewis bef3f11150 Use git date instead of server date
continuous-integration/drone/pr Build is pending Details
continuous-integration/drone/push Build is running Details
2023-01-10 17:55:37 -08:00
Sarah Jamie Lewis b29293334d Update 'Makefile'
continuous-integration/drone/pr Build is pending Details
2023-01-11 01:44:24 +00:00
Sarah Jamie Lewis 9da33c3083 Update '.drone.yml'
continuous-integration/drone/pr Build is pending Details
continuous-integration/drone/push Build is running Details
2023-01-10 23:39:45 +00:00
Sarah Jamie Lewis 3d0a3a5a49 Fix File Downloading on Android
continuous-integration/drone/pr Build was killed Details
continuous-integration/drone/push Build is passing Details
2022-12-12 14:51:41 -08:00
Sarah Jamie Lewis 1e4221c6bd Merge pull request 'use new CreateProfile with attributes and save autosave' (#106) from saveAutosave into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #106
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-12-11 17:28:21 +00:00
Dan Ballard 973e73a308 use new CreateProfile with attributes and save autosave
continuous-integration/drone/pr Build is running Details
2022-12-11 09:07:08 -08:00
Sarah Jamie Lewis ff20656e22 Move profile image launching to ProtocolEngineStart event
continuous-integration/drone/pr Build is running Details
continuous-integration/drone/push Build is passing Details
2022-12-07 13:46:15 -08:00
Sarah Jamie Lewis e12cb2c965 Remove Directly Sharing a Profile Image, use general ReshareFiles instead
continuous-integration/drone/pr Build is pending Details
2022-12-07 10:48:12 -08:00
Sarah Jamie Lewis 54ba8c463a Move Restart File Shares to After Activate Peer Engine
continuous-integration/drone/pr Build is pending Details
2022-12-07 10:39:34 -08:00
Sarah Jamie Lewis 137027d011 Merge pull request 'cwtch bump' (#104) from lcgBump into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #104
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-12-06 06:24:56 +00:00
Dan Ballard 916ca279ea cwtch bump
continuous-integration/drone/pr Build is running Details
2022-12-05 21:44:51 -08:00
Sarah Jamie Lewis 0d05a0731c Merge pull request 'activateEngine' (#103) from activateEngine into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #103
2022-12-05 18:24:05 +00:00
Dan Ballard e7e9a71515 newest cwtch and add new savable profile attribute of local.profile.autostart
continuous-integration/drone/pr Build is running Details
2022-12-05 10:08:09 -08:00
Dan Ballard 6021daeaca add (De)ActivateEngine API calls; support profile autostart 2022-12-04 19:49:02 -08:00
Sarah Jamie Lewis 92ec4c6667 Update Profile Image Timestamp on Startup so Images get Reshared
continuous-integration/drone/pr Build is pending Details
continuous-integration/drone/push Build is passing Details
2022-12-04 09:02:37 -08:00
Sarah Jamie Lewis d28d0db77c Merge pull request 'use new Cwtch ActiveEngines' (#101) from activateEngine into trunk
continuous-integration/drone/push Build is pending Details
Reviewed-on: #101
2022-12-04 17:01:49 +00:00
Dan Ballard 18c6907dbe use new Cwtch ActiveEngines
continuous-integration/drone/pr Build is running Details
2022-12-03 23:10:13 -08:00
Sarah Jamie Lewis c88700b226 Merge pull request 'Update Cwtch' (#100) from cwtch_update into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #100
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-11-30 18:47:20 +00:00
Sarah Jamie Lewis 1f3617cce6 Update Windows and Android Containers
continuous-integration/drone/pr Build is running Details
2022-11-30 10:26:10 -08:00
Sarah Jamie Lewis 3a15d75011 Remove golint from drone
continuous-integration/drone/pr Build is running Details
2022-11-30 09:06:20 -08:00
Sarah Jamie Lewis 482cb54263 Update drone to use Go 1.19.1
continuous-integration/drone/pr Build is running Details
2022-11-30 09:02:38 -08:00
Sarah Jamie Lewis ec467116b1 Update Cwtch
continuous-integration/drone/pr Build is running Details
2022-11-30 08:58:29 -08:00
Dan Ballard 397d264bd9 Merge pull request 'go.sum' (#99) from update-retry into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #99
2022-09-10 19:30:24 +00:00
Sarah Jamie Lewis 1a25b45bcf Merge branch 'trunk' into update-retry
continuous-integration/drone/pr Build is pending Details
2022-09-10 19:29:02 +00:00
Sarah Jamie Lewis 989cc25c93 go.sum
continuous-integration/drone/pr Build is pending Details
2022-09-10 12:28:30 -07:00
Dan Ballard 9ef5cbc911 Merge pull request 'update-retry' (#98) from update-retry into trunk
continuous-integration/drone/push Build is failing Details
Reviewed-on: #98
2022-09-10 19:18:26 +00:00
Sarah Jamie Lewis 39eaa5c8c3 upgrade cwtch, fix acn reset
continuous-integration/drone/pr Build is pending Details
2022-09-10 12:12:17 -07:00
Sarah Jamie Lewis f0ea513177 Update Cwtch / Trigger Antispam PLugin 2022-09-10 10:51:49 -07:00
Dan Ballard e0d2c229c7 Merge pull request 'Update Cwtch and Expose new Token Service APIS' (#97) from surface-tokens into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #97
2022-09-09 18:08:35 +00:00
Sarah Jamie Lewis 2bd7a2658e Add hashes
continuous-integration/drone/pr Build is running Details
2022-09-09 09:46:47 -07:00
Sarah Jamie Lewis 67e58b1613 Update go.mod for android
continuous-integration/drone/pr Build was killed Details
2022-09-09 09:44:43 -07:00
Sarah Jamie Lewis 079578c172 Fix comment 2022-09-09 09:44:23 -07:00
Sarah Jamie Lewis 2bcadca55f Update Cwtch - Expose new Token Service Status Events 2022-09-09 09:44:19 -07:00
Dan Ballard 2f188b3a46 Merge pull request 'app event handler now turns app networking on/off based on ACN status' (#96) from networkAfterOnline into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #96
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-09-09 16:43:02 +00:00
Dan Ballard f75286cb97 do networking after acn online; depupgrades
continuous-integration/drone/pr Build is pending Details
2022-09-09 09:42:47 -07:00
Dan Ballard 61c7418252 app event handler now turns app networking on/off based on ACN status 2022-09-08 21:35:29 -07:00
Dan Ballard 99a51ef19a Merge pull request 'filesharing-fixes' (#95) from filesharing-fixes into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #95
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-09-07 17:00:53 +00:00
Sarah Jamie Lewis f66921b5ce Format
continuous-integration/drone/pr Build is passing Details
2022-08-26 10:58:18 -07:00
Sarah Jamie Lewis 2058a51579 Don't shadow file sharing functionality error
continuous-integration/drone/pr Build was killed Details
2022-08-26 10:57:35 -07:00
Sarah Jamie Lewis 085b414bd8 Don't autodownload images if download folder doesn't exist
continuous-integration/drone/pr Build is passing Details
2022-08-26 10:48:04 -07:00
Sarah Jamie Lewis e83369d4cc Add checks for download folder existence prior to downloading 2022-08-24 14:44:42 -07:00
Sarah Jamie Lewis f1de9b1951 Merge pull request 'import bundle now returns result' (#94) from importBundleRet into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #94
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-08-16 06:17:52 +00:00
Dan Ballard 251f757c5f import bundle now returns result
continuous-integration/drone/pr Build is passing Details
2022-08-15 22:20:48 -07:00
Sarah Jamie Lewis b99e35ed03 Merge pull request 'connectivty/cwtch bump + ACN Version' (#93) from smallThings into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #93
2022-08-08 19:55:21 +00:00
Dan Ballard 10d9059d49 resetTor does a full replace, add a QueryACNVersion to get the new version
continuous-integration/drone/pr Build is passing Details
2022-08-08 12:35:19 -07:00
Dan Ballard 2d9a448b52 fix group notifications; connectivity/cwtch ACNVersion event; antidup contact on import from cwtch 2022-08-05 20:45:16 -07:00
Dan Ballard 7b3e842715 Merge pull request 'Add Attribute Map to Contact Struct' (#92) from pinned into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #92
2022-07-22 16:34:36 +00:00
Sarah Jamie Lewis f2ea1ec84d Merge branch 'trunk' into pinned
continuous-integration/drone/pr Build is passing Details
2022-07-21 16:55:32 +00:00
Sarah Jamie Lewis bf36df8de8 Add Attribute Map to Contact Struct
continuous-integration/drone/pr Build is pending Details
2022-07-21 09:54:40 -07:00
Sarah Jamie Lewis 44173471c8 Merge pull request 'New File Sharing APIs' (#91) from filesharing-persist into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #91
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-07-06 19:48:26 +00:00
Sarah Jamie Lewis 7e01cf4916 Reshare Files on Enabling File Sharing
continuous-integration/drone/pr Build is passing Details
2022-07-06 12:20:50 -07:00
Sarah Jamie Lewis f119d316c5 Update Cwtch, Expose New File Sharing APIs
continuous-integration/drone/pr Build is passing Details
2022-07-06 11:33:12 -07:00
Sarah Jamie Lewis a558ce67d6 Turn message formatting experiment on by default 2022-07-06 11:33:12 -07:00
Sarah Jamie Lewis 7069fab0b1 Merge pull request 'squash notifications on group messages while syncing' (#90) from squashSyncNotif into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #90
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-06-23 20:09:40 +00:00
Dan Ballard 1efb0d076b squash notifications on group messages while syncing
continuous-integration/drone/pr Build is passing Details
2022-06-23 12:08:20 -07:00
Sarah Jamie Lewis 231e27d116 Merge pull request 'fix mac deploy' (#89) from macosarm64 into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #89
2022-06-22 19:35:45 +00:00
Sarah Jamie Lewis 1e4e2368f9 Merge branch 'trunk' into macosarm64
continuous-integration/drone/pr Build was killed Details
2022-06-22 19:35:27 +00:00
Dan Ballard b98162dc3c mac arm64
continuous-integration/drone/pr Build is running Details
2022-06-22 12:34:01 -07:00
Dan Ballard 9895a37f2f fix mac deploy
continuous-integration/drone/pr Build was killed Details
2022-06-22 12:23:41 -07:00
Sarah Jamie Lewis e70e0f8f2f Merge pull request 'add drone step for macos arm64' (#88) from macosarm64 into trunk
continuous-integration/drone/push Build was killed Details
Reviewed-on: #88
2022-06-22 19:14:51 +00:00
Dan Ballard 46b34f0a60 pull in windows build notes from pr 67
continuous-integration/drone/pr Build is passing Details
2022-06-22 12:11:42 -07:00
Dan Ballard 07b496fc48 macos name both libs by arch
continuous-integration/drone/pr Build is running Details
2022-06-22 11:41:51 -07:00
Dan Ballard b3bb69829a add drone step for macos arm64
continuous-integration/drone/pr Build was killed Details
2022-06-22 09:50:45 -07:00
Dan Ballard ff23465f84 Merge pull request 'Fix Invalid Timestamp in Cached Messages' (#87) from time_fix into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #87
2022-06-21 22:40:08 +00:00
Sarah Jamie Lewis 26f8f8fcfd Fix Invalid Timestamp in Cached Messages
continuous-integration/drone/pr Build was killed Details
2022-06-21 15:27:31 -07:00
Dan Ballard 02c7b0b962 Merge pull request 'Upgrade Dependencies, include Memory Profile in debug info' (#86) from debugmeminfo into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #86
2022-04-21 23:11:38 +00:00
Sarah Jamie Lewis 0474d5f327 Update Readme
continuous-integration/drone/pr Build was killed Details
2022-04-21 16:10:27 -07:00
Sarah Jamie Lewis e029076b20 Upgrad Cwtch - Wrap Profiling
continuous-integration/drone/pr Build is pending Details
2022-04-21 16:05:55 -07:00
Sarah Jamie Lewis 7c2cc61b62 Upgrade Dependencies, include Memory Profile in debug info
continuous-integration/drone/pr Build is passing Details
2022-04-20 17:19:17 -07:00
Sarah Jamie Lewis d8ed0bf57c Merge pull request 'add lastSeenMessageId got contact' (#85) from lastSeenMid into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #85
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-04-20 00:19:20 +00:00
Dan Ballard 352e362111 add lastSeenMessageId got contact
continuous-integration/drone/pr Build is passing Details
2022-04-19 16:52:21 -07:00
Dan Ballard c32d5082e4 Merge pull request 'fix retVal squash logic so remote vals dont override local vals and get sent up' (#84) from squshRet into trunk
continuous-integration/drone/push Build is pending Details
Reviewed-on: #84
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-04-18 19:57:15 +00:00
Dan Ballard 89f8ec0253 fix retVal squash logic so remote vals dont override local vals and get sent up
continuous-integration/drone/pr Build is passing Details
2022-04-18 09:47:39 -07:00
Sarah Jamie Lewis 9901e081e4 Merge pull request 'DebugInfo command (also upgrade Cwtch)' (#83) from debuginfo into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #83
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-04-14 22:13:51 +00:00
Sarah Jamie Lewis 58029ee79e DebugInfo command
continuous-integration/drone/pr Build is passing Details
2022-04-14 14:54:31 -07:00
Dan Ballard 3d8ef9f06b Merge pull request 'include ACL struct in relevant conversation events' (#82) from acl into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #82
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-04-06 23:25:18 +00:00
Dan Ballard 8d00248aa8 include ACL struct in relevant conversation events
continuous-integration/drone/pr Build is pending Details
2022-04-06 16:16:50 -07:00
Dan Ballard 3ad0bc904c Merge pull request 'add get[Profile|Conversation]Attribute api' (#81) from getAttr into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #81
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-04-05 00:48:54 +00:00
Dan Ballard cfd8fe21c8 add get[Profile|Conversation]Attribute api
continuous-integration/drone/pr Build is passing Details
2022-04-04 17:22:59 -07:00
Dan Ballard 97defdf965 Merge pull request 'add support for storing and using lastMessageSeen Time from ui and using to calculate unread counts' (#80) from unreadSync into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #80
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-04-04 21:45:15 +00:00
Dan Ballard cd48642411 add support for storing and using lastMessageSeen Time from ui and using to calculate unread counts
continuous-integration/drone/pr Build is passing Details
2022-04-01 15:52:14 -07:00
Sarah Jamie Lewis 1acae32030 Merge pull request 'GetMessages api; send[message|file|invite] return message as json' (#79) from sendRetMsg into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #79
2022-03-23 23:04:53 +00:00
Dan Ballard 98eae2e6ff GetMessages api; send[message|file|invite] return message as json
continuous-integration/drone/pr Build is passing Details
2022-03-23 15:42:46 -07:00
Dan Ballard ca4897b191 Merge pull request 'Enable Network Health Plugin. Fix Default Group Image Bug' (#78) from nc into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #78
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-03-22 20:11:23 +00:00
Sarah Jamie Lewis 3f431d9f18 Enable Network Health Plugin. Fix Default Group Image Bug
continuous-integration/drone/pr Build is passing Details
2022-03-22 13:02:20 -07:00
Dan Ballard 5b34715f8c Merge pull request 'import_export' (#76) from import_export into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #76
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2022-03-11 00:04:37 +00:00
Sarah Jamie Lewis 31dda072e5 Import and Export Profile
continuous-integration/drone/pr Build is passing Details
This commit also adds some guard rails around calling functions without a proper backing profile.
2022-03-10 14:27:45 -08:00
Sarah Jamie Lewis 68c976107d Import and Export Profile 2022-03-10 14:27:45 -08:00
Sarah Jamie Lewis c2874db3c0 Merge pull request 'add started() is lcg initialized check api; prevcent reconnect from launching dup peer message forwarding; remove unused MessageCounterResync' (#77) from started into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #77
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-03-10 22:24:48 +00:00
Dan Ballard 7ace298d6e add started() is lcg initialized check api; prevcent reconnect from launching dup peer message forwarding; remove unused MessageCounterResync
continuous-integration/drone/pr Build is passing Details
2022-03-10 14:09:52 -08:00
Dan Ballard 4b881b9a12 Merge pull request 'add build date and version info; add server sync state data' (#75) from state into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #75
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-03-04 00:52:50 +00:00
Dan Ballard f1c43f44ca add build date and version info; add server sync state data
continuous-integration/drone/pr Build is passing Details
2022-03-03 16:34:39 -08:00
Sarah Jamie Lewis e8b2def3a4 Merge pull request 'fix default notification policy in settings' (#74) from mute into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #74
2022-02-23 21:58:47 +00:00
Dan Ballard 5af4317851 fix default notification policy in settings
continuous-integration/drone/pr Build is passing Details
2022-02-23 11:32:21 -08:00
Sarah Jamie Lewis a6277fc998 Merge pull request 'fix notification settings for groups' (#73) from fixNotifyGroup into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #73
2022-02-09 21:21:35 +00:00
Dan Ballard 11fbb17bfd fix notification settings for groups
continuous-integration/drone/pr Build is passing Details
2022-02-09 16:17:51 -05:00
Sarah Jamie Lewis d0d5300a95 Merge pull request 'notificationPolicy' (#72) from notificationPolicy into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #72
2022-02-08 22:33:45 +00:00
Dan Ballard 419c39cc68 Merge branch 'trunk' into notificationPolicy
continuous-integration/drone/pr Build is passing Details
2022-02-08 17:15:31 -05:00
erinn 4467c40e17 Merge pull request 'Fixup Logic for Custom Profile Image Downloads (restrict to Accepted contacts), stronger defaults' (#71) from profile_images_bugfixes into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #71
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-02-08 21:17:31 +00:00
Sarah Jamie Lewis db8e43cb05 fixup filekey.complete checks to check the actual value instead of just existence
continuous-integration/drone/pr Build is pending Details
2022-02-08 13:13:33 -08:00
Sarah Jamie Lewis 50b7a43466 Check complete status against file existence
continuous-integration/drone/pr Build is pending Details
2022-02-08 13:09:04 -08:00
Sarah Jamie Lewis 08774268a8 simplify profile image download if case
continuous-integration/drone/pr Build is pending Details
2022-02-08 12:59:33 -08:00
Sarah Jamie Lewis 8040385681 Fixup Logic for Custom Profile Image Downloads (restrict to Accepted contacts), stronger defaults
continuous-integration/drone/pr Build is passing Details
2022-02-08 12:47:36 -08:00
Dan Ballard 758af8dcaf rejig notification policies around mute, opt in, default always and conversations around default, never, optin 2022-02-08 11:52:55 -05:00
Dan Ballard ce09ccdd6a PR comments: enumerification 2022-02-08 11:52:55 -05:00
Dan Ballard e5e4d21fa0 adding support for settings for notification policy and content, per convo opt in/outs, and attaching relevant info to messages 2022-02-08 11:52:09 -05:00
erinn 17acc3b8ef Merge pull request 'Add DefaultPicture parameter to Contact and Profiles' (#70) from profile_pictures into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #70
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-02-07 22:29:33 +00:00
erinn 942b8b4709 Merge branch 'trunk' into profile_pictures
continuous-integration/drone/pr Build is pending Details
2022-02-07 22:29:22 +00:00
Sarah Jamie Lewis 44e5c38aa6 Add DefaultPicture parameter to Contact and Profiles
continuous-integration/drone/pr Build is passing Details
2022-02-07 14:21:52 -08:00
erinn 4e4e3315dd Merge pull request 'Profile Images (+ Testing Improvements)' (#68) from profile_images into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #68
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-02-04 21:56:35 +00:00
Sarah Jamie Lewis a9563b615c Remove mobile from godep
continuous-integration/drone/pr Build is running Details
2022-02-04 13:49:19 -08:00
Sarah Jamie Lewis fc9999f835 Upgrade Cwtch
continuous-integration/drone/pr Build is failing Details
2022-02-04 13:33:28 -08:00
Sarah Jamie Lewis 2f3db01c2f Restrict Downloads to Max Sizes (for both default and image / profile previews)
continuous-integration/drone/pr Build is pending Details
2022-02-04 12:48:39 -08:00
Sarah Jamie Lewis d40900481a remove old testing code
continuous-integration/drone/pr Build is pending Details
2022-02-03 16:22:26 -08:00
Sarah Jamie Lewis 2e9f9fb14f Update Cwtch with new ShareFile API
continuous-integration/drone/pr Build is pending Details
2022-02-03 16:11:40 -08:00
Sarah Jamie Lewis 2bef622860 Enable Sharing of Profile Images / Autodownloading of Profile Images
continuous-integration/drone/pr Build is passing Details
2022-02-03 15:17:15 -08:00
erinn e1073be7d2 Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into testfixes 2022-01-27 15:43:56 -08:00
erinn d77d7bbc52 Merge pull request 'Upgrade Cwtch' (#66) from fastercwtch into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #66
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-01-26 20:07:22 +00:00
Sarah Jamie Lewis 240c5c232d Upgrade Cwtch
continuous-integration/drone/pr Build is passing Details
2022-01-26 12:04:23 -08:00
erinn e0e1a4bf28 Merge pull request 'Upgrade Cwtch' (#65) from sender_previews into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #65
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-01-20 22:20:56 +00:00
Sarah Jamie Lewis 5e271d0f3c Upgrade Cwtch
continuous-integration/drone/pr Build is passing Details
2022-01-20 13:58:28 -08:00
Dan Ballard 6865ec1ec8 Merge pull request 'symantic arg changes in GetMessageByID; GetMessagesByContentHash cleanup and streamline, returns singled EnhancedMessage with LocalIndex' (#64) from getMsg into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #64
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-01-20 17:51:43 +00:00
Dan Ballard 82a801678b add more ContentHash to get*Message* functions, upgrade cwtch for the same
continuous-integration/drone/pr Build is passing Details
2022-01-20 12:37:39 -05:00
Dan Ballard c58be05110 symantic arg changes in GetMessageByID; GetMessagesByContentHash cleanup and streamline, returns singled EnhancedMessage with LocalIndex
continuous-integration/drone/pr Build is pending Details
2022-01-20 00:51:54 -05:00
Dan Ballard 84d451fb46 Merge pull request 'Fix Tor Reset to Update Settings and Avoid Contention on datadir' (#63) from custom_tor_config into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #63
2022-01-19 21:09:04 +00:00
Sarah Jamie Lewis 5e4e3d4083 Remove Settings Log
continuous-integration/drone/pr Build is passing Details
2022-01-19 13:00:32 -08:00
Sarah Jamie Lewis 0db0610a23 Fix Tor Reset to Update Settings and Avoid Contention on datadir 2022-01-19 13:00:01 -08:00
Dan Ballard 2aea700ebd Merge pull request 'Allow Caching of Tor Data Directories' (#62) from custom_tor_config into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #62
2022-01-18 21:23:06 +00:00
Sarah Jamie Lewis 85af1ad3ba path -> filepath
continuous-integration/drone/pr Build is passing Details
2022-01-18 13:04:38 -08:00
Sarah Jamie Lewis 799fc6e621 Allow Caching of Tor Data Directories
continuous-integration/drone/pr Build is pending Details
- Also deletes unused data directories on startup.
2022-01-18 12:50:22 -08:00
erinn 4cf95d6507 Merge pull request 'Upgrade Cwtch + Expose ACNInfo Events' (#61) from custom_tor_config into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #61
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-01-17 22:18:03 +00:00
Sarah Jamie Lewis dde5b2b1e8 Upgrade Cwtch + Expose ACNInfo Events
continuous-integration/drone/pr Build is passing Details
2022-01-17 12:38:01 -08:00
erinn c098df5db3 Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into testfixes 2022-01-13 14:42:36 -08:00
erinn 1df0ba54f7 wip 2022-01-13 14:42:31 -08:00
erinn af47036b4e Merge pull request 'Support Custom Tor Configuration' (#60) from custom_tor_config into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #60
Reviewed-by: erinn <erinn@openprivacy.ca>
2022-01-12 22:24:39 +00:00
Sarah Jamie Lewis 0eb7a91d26 Fix logging of ACN
continuous-integration/drone/pr Build is passing Details
2022-01-12 14:11:35 -08:00
Sarah Jamie Lewis 6ad7a41b35 Support Custom Tor Configuration
continuous-integration/drone/pr Build is failing Details
2022-01-12 14:02:50 -08:00
Sarah Jamie Lewis 24bcd72e75 Merge pull request 'NewPeer enrichment of conversations: group use groupServer state' (#59) from groupStatus into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #59
2022-01-07 18:36:28 +00:00
Dan Ballard f2067348ec NewPeer enrichment of conversations: group use groupServer state
continuous-integration/drone/pr Build is passing Details
2022-01-07 11:32:46 -05:00
Dan Ballard f1d2e6a310 Merge pull request 'add caching and filtering of contact state change events; change logic from contact auth to approved/blocked' (#58) from fixAcceptblock into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #58
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-01-06 22:10:28 +00:00
Dan Ballard 4da1cb70df Merge branch 'trunk' into fixAcceptblock
continuous-integration/drone/pr Build is pending Details
2022-01-06 22:10:16 +00:00
Dan Ballard 86dfe63a8f add caching and filtering of contact state change events; change logic from contact auth to approved/blocked
continuous-integration/drone/pr Build is pending Details
2022-01-06 17:09:49 -05:00
Sarah Jamie Lewis 9c32586068 Merge pull request 'pass along storage migration messages' (#57) from migrateMessage into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #57
2022-01-05 17:05:26 +00:00
Dan Ballard fa42ce1fb1 Merge branch 'trunk' into migrateMessage
continuous-integration/drone/pr Build is passing Details
2022-01-04 23:54:45 +00:00
Dan Ballard a1e06a868f Merge pull request 'don't fetch metrics for non running servers' (#56) from lastFixes into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #56
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-12-20 23:35:31 +00:00
Dan Ballard 6fb5234724 pin drone container version to deal with docker hub instability
continuous-integration/drone/pr Build is passing Details
2021-12-20 18:22:44 -05:00
Dan Ballard 8598802abd don't fetch metrics for non running servers
continuous-integration/drone/pr Build encountered an error Details
2021-12-20 18:12:34 -05:00
Dan Ballard 95c36703cc Merge pull request 'Remove SendMessageTo*Errors / Upgrade Cwtch' (#55) from change_password into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #55
2021-12-19 20:56:07 +00:00
Sarah Jamie Lewis 9e575f6801 Merge branch 'trunk' into change_password
continuous-integration/drone/pr Build is passing Details
2021-12-19 20:36:50 +00:00
Sarah Jamie Lewis 32c3d93e4d Upgrade Cwtch
continuous-integration/drone/pr Build is pending Details
2021-12-19 12:36:09 -08:00
Sarah Jamie Lewis 75a31fd096 Merge pull request 'fix some name sync behaviour' (#54) from syncName into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #54
2021-12-19 20:33:43 +00:00
Dan Ballard ba4b31f06b fix some name sync behaviour
continuous-integration/drone/pr Build is passing Details
2021-12-19 13:52:10 -05:00
Sarah Jamie Lewis ab2375e57c Upgrade Cwtch and Remove SendMessageFrom*Error 2021-12-18 18:13:12 -08:00
Sarah Jamie Lewis 68c02502a2 Merge pull request 'change_password' (#53) from change_password into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #53
Reviewed-by: erinn <erinn@openprivacy.ca>
2021-12-19 01:30:40 +00:00
Sarah Jamie Lewis 597b09dba9 go mod tidy
continuous-integration/drone/pr Build is passing Details
2021-12-18 17:26:04 -08:00
Sarah Jamie Lewis d6c1b386a9 Change Password API
continuous-integration/drone/pr Build is passing Details
2021-12-18 17:23:43 -08:00
Sarah Jamie Lewis 212e71a1b9 ChangePassword APIs 2021-12-18 17:22:59 -08:00
Sarah Jamie Lewis 306c074e7e Upgrade Cwtch and Server 2021-12-18 17:22:31 -08:00
Sarah Jamie Lewis e4244aeb31 Merge pull request 'image previews' (#51) from ipreview into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #51
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-12-19 01:21:40 +00:00
erinn 11bbc3aa78 bump cwtch and fix miscommits
continuous-integration/drone/pr Build is pending Details
2021-12-18 17:20:08 -08:00
erinn f4ff802460 image previews sarah comments
continuous-integration/drone/pr Build is pending Details
2021-12-18 17:16:21 -08:00
erinn 8b38a8b159 Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into ipreview 2021-12-18 16:42:48 -08:00
Sarah Jamie Lewis a3707bcadb Merge pull request 'cwtch upgrade dropping unused events; android build notes' (#52) from cwtchUp into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #52
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-12-18 21:54:24 +00:00
Dan Ballard 4903e9376b fix logic error on loading peer
continuous-integration/drone/pr Build is passing Details
2021-12-18 16:31:52 -05:00
Dan Ballard d30052176b pass along storage migration messages
continuous-integration/drone/pr Build is passing Details
2021-12-17 19:56:38 -05:00
Dan Ballard 4c48fd603d cwtch upgrade dropping unused events; android build notes
continuous-integration/drone/pr Build is pending Details
2021-12-17 15:38:26 -05:00
erinn eb33f11127 message previews - remove debug
continuous-integration/drone/pr Build is pending Details
2021-12-16 16:50:21 -08:00
erinn d59d54ab6a image previews 2021-12-16 16:43:23 -08:00
erinn cac25c0d67 Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into ipreview 2021-12-14 13:29:08 -08:00
erinn 1b0333d468 wip image previews 2021-12-14 13:23:32 -08:00
Sarah Jamie Lewis aa102bd169 Merge pull request 'fix server description; fix serverInfo to have identifier; add themeMode to settings; cwtch bump' (#50) from minorFixs into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #50
2021-12-11 05:50:59 +00:00
Dan Ballard d2abed7583 fix server description; fix serverInfo to have identifier; add themeMode to settings; cwtch bump
continuous-integration/drone/pr Build is passing Details
2021-12-10 16:28:13 -08:00
Sarah Jamie Lewis 28a13aaca9 Merge pull request 'server metrics' (#49) from serverStats into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #49
2021-12-08 05:31:19 +00:00
Dan Ballard 9eadc77afd cwtch and server updates
continuous-integration/drone/pr Build is passing Details
2021-12-07 19:00:10 -08:00
Dan Ballard 69df789355 add support for server metrics; delete eventhandler dup fn for push(); make server response to settings change stateful 2021-12-07 18:59:53 -08:00
Dan Ballard 37eb9f681a minor support to manage profile servers 2021-12-07 18:54:09 -08:00
Sarah Jamie Lewis 5d7f45e50d Merge pull request 'minor support to manage profile servers' (#48) from manageProfileServers into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #48
2021-12-08 02:52:04 +00:00
Dan Ballard 35abad7224 cwtch attribute changes
continuous-integration/drone/pr Build is passing Details
2021-12-07 18:21:24 -08:00
Dan Ballard 25d035267a minor support to manage profile servers 2021-12-07 18:13:56 -08:00
Sarah Jamie Lewis 79a87b78e0 Merge pull request 'libCwtch-go changes for storage engine refactor and profile api changes' (#47) from cwtch_refactor into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #47
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2021-12-08 00:44:03 +00:00
Sarah Jamie Lewis a43c225267 Cleaning up group functionality after merge
continuous-integration/drone/pr Build is passing Details
2021-12-07 13:49:20 -08:00
Sarah Jamie Lewis 8e80dbaf78 Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into cwtch_refactor
continuous-integration/drone/pr Build is failing Details
2021-12-07 13:43:08 -08:00
Sarah Jamie Lewis 1aea1c6e5f Upgrade Cwtch and Server
continuous-integration/drone/pr Build is pending Details
2021-12-07 13:40:24 -08:00
Sarah Jamie Lewis 62f3d8878e Reset to lib
continuous-integration/drone/pr Build is pending Details
2021-12-06 12:23:57 -08:00
Sarah Jamie Lewis fee6c7e641 Fixup Event Handling for UI Cache
continuous-integration/drone/pr Build is pending Details
2021-12-06 12:22:49 -08:00
Sarah Jamie Lewis e31d31d76f Further clarifications on Event Model, Support for Attributes in Message APIs
continuous-integration/drone/pr Build is pending Details
2021-12-01 04:16:15 -08:00
Sarah Jamie Lewis b0f54bb169 SetMessageAttribute + Fallback to handle for new messages 2021-11-30 13:32:01 -08:00
Sarah Jamie Lewis bd176f89cd Prefer local overrides
continuous-integration/drone/pr Build is pending Details
2021-11-26 15:07:20 -08:00
Sarah Jamie Lewis 92d2925622 NewMessageByID, Suppress Network Tests
continuous-integration/drone/pr Build is pending Details
2021-11-26 14:26:26 -08:00
Sarah Jamie Lewis edff87f77c Updates to GetMessageByContentHash
continuous-integration/drone/pr Build is pending Details
2021-11-23 14:30:16 -08:00
Sarah Jamie Lewis 6723bdf558 GetMessagesByContentHash + Other API Fixes
continuous-integration/drone/pr Build is failing Details
2021-11-19 11:50:37 -08:00
Sarah Jamie Lewis 3cc56fb011 Fixes from Cwtch UI Integration 2021-11-18 15:44:21 -08:00
Sarah Jamie Lewis b2da9fc54d First compilation with new cwtch API 2021-11-17 14:34:35 -08:00
Sarah Jamie Lewis dcdbf382cb Updated Cwtch Refactor 2021-11-17 12:33:51 -08:00
Sarah Jamie Lewis 7f5d466d49 Merge pull request 'servers bump to 1.3.4 (fix windows crash in monitors)' (#46) from serversBump into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #46
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-09 23:23:27 +00:00
Dan Ballard 3efc9543a4 servers bump to 1.3.4 (fix windows crash in monitors)
continuous-integration/drone/pr Build is passing Details
2021-11-09 15:08:00 -08:00
Sarah Jamie Lewis 3d3e127520 Merge pull request 'on server import, connect' (#45) from fixFirstJoin into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #45
2021-11-06 00:09:40 +00:00
Dan Ballard bbd6748d06 on server import, connect
continuous-integration/drone/pr Build is passing Details
2021-11-05 16:40:48 -07:00
Sarah Jamie Lewis 86c5a51b22 Merge pull request 'make server functionality create servers dir on init' (#44) from macosBuild into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #44
2021-11-05 20:33:52 +00:00
Dan Ballard e966392233 path -> filepath
continuous-integration/drone/pr Build is passing Details
2021-11-05 13:21:48 -07:00
Dan Ballard d519a4d0b2 fix perms
continuous-integration/drone/pr Build is passing Details
2021-11-05 16:16:13 -04:00
Dan Ballard 85a90658b9 server functionality init create servers directory 2021-11-05 13:05:45 -07:00
Sarah Jamie Lewis 81705ce48f Merge pull request 'testing drone support for macos' (#43) from macosBuild into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #43
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-04 23:58:35 +00:00
Sarah Jamie Lewis 3386afd3b5 Merge branch 'trunk' into macosBuild
continuous-integration/drone/pr Build is pending Details
2021-11-04 23:58:26 +00:00
Dan Ballard 2b2adb01e3 test macos drone deploy
continuous-integration/drone/pr Build is passing Details
2021-11-04 16:11:21 -07:00
Sarah Jamie Lewis 706be7fc38 Merge pull request 'file resumption support' (#42) from filey into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #42
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-04 22:42:03 +00:00
erinn b56b821b19 update cwtch
continuous-integration/drone/pr Build is passing Details
2021-11-04 15:29:39 -07:00
Dan Ballard 2f1fe86d50 testing drone support for macos
continuous-integration/drone/pr Build is running Details
2021-11-04 14:53:02 -07:00
erinn 0bd369888f Merge branch 'trunk' of git.openprivacy.ca:cwtch.im/libcwtch-go into filey
continuous-integration/drone/pr Build is passing Details
2021-11-04 14:10:29 -07:00
erinn 792e84d5f9 file resumption support 2021-11-04 14:10:21 -07:00
Dan Ballard 4adb501a89 Merge pull request 'support to delete a server' (#41) from deleteServer into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #41
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-04 04:18:40 +00:00
Dan Ballard b3d3464e1e support to delete a server
continuous-integration/drone/pr Build is passing Details
2021-11-03 21:13:15 -07:00
Dan Ballard b47b27008e Merge pull request 'Upgrade Cwtch' (#40) from p2p_timeline_fix into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #40
2021-11-03 19:27:44 +00:00
Sarah Jamie Lewis 06d51fb0bb Upgrade Cwtch
continuous-integration/drone/pr Build is passing Details
2021-11-03 12:16:22 -07:00
Sarah Jamie Lewis f3463d54d3 Merge pull request 'on createServer autostart after create' (#39) from autolaunchAfterCreate into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #39
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-03 18:58:54 +00:00
Dan Ballard 77a5cc3a86 on createServer autostart after create
continuous-integration/drone/pr Build is passing Details
2021-11-03 11:56:25 -07:00
Sarah Jamie Lewis 17ab80f09c Merge pull request 'fix logic error in DeactivateServers that prevented Stop calls when experiment turned off' (#38) from experimentKillServe into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #38
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-03 17:52:39 +00:00
Dan Ballard 9f7ffb50f9 fix logic error in DeactivateServers that prevented Stop calls when experiment turned off
continuous-integration/drone/pr Build is passing Details
2021-11-03 10:50:20 -07:00
erinn d5231b13db merge 2021-11-02 15:05:01 -07:00
erinn 777d564ca4 wip: file retries 2021-11-02 14:31:14 -07:00
Sarah Jamie Lewis baddf633b2 Merge pull request 'LoadServers launches autolaunchers' (#36) from servers into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #36
2021-11-02 19:09:56 +00:00
Sarah Jamie Lewis ac00e2195e Merge branch 'trunk' into servers
continuous-integration/drone/pr Build is passing Details
2021-11-02 18:58:49 +00:00
Dan Ballard f9f074a65c LoadServers launches autolaunchers
continuous-integration/drone/pr Build is passing Details
2021-11-01 21:30:03 -07:00
Dan Ballard 63e96f32bf Merge pull request 'first pass of server functionality API' (#33) from servers into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #33
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2021-11-02 02:51:59 +00:00
Dan Ballard f3b753827f better support reloading servers on experiment enable/disable
continuous-integration/drone/pr Build is passing Details
2021-11-01 19:36:14 -07:00
Dan Ballard 063ad61e36 move from Shutdown to Stop/Destroy, remove enabled in favor of running from CheckStatus
continuous-integration/drone/pr Build is passing Details
2021-11-01 18:56:08 -07:00
Dan Ballard c8f19b3e4c incluce features/servers 2021-11-01 18:53:11 -07:00
Dan Ballard 5b72edebad cleaning up server API 2021-11-01 18:53:11 -07:00
Dan Ballard a237314d5f first pass of server functionality API 2021-11-01 18:52:28 -07:00
erinn 4529984e45 Merge pull request 'Upgrade Cwtch - rely on Cwtch methods for fetching group timelines.' (#35) from new_group_api into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #35
Reviewed-by: erinn <erinn@openprivacy.ca>
2021-11-01 22:00:26 +00:00
Sarah Jamie Lewis 041bdcf97b Merge branch 'trunk' into new_group_api
continuous-integration/drone/pr Build is passing Details
2021-11-01 21:55:07 +00:00
Sarah Jamie Lewis a36e439589 Upgrade Cwtch - rely on Cwtch methods for fetching group timelines.
continuous-integration/drone/pr Build is passing Details
2021-11-01 14:11:30 -07:00
Dan Ballard 9fdbd45bb2 Merge pull request 'Convert to new ScopedZone Interface' (#34) from scopezone into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #34
2021-10-27 19:52:26 +00:00
Sarah Jamie Lewis a3e3c221ca upgrade cwtch
continuous-integration/drone/pr Build is passing Details
2021-10-27 09:35:33 -07:00
Sarah Jamie Lewis 0f5d0389ca Use localname when loading a profile as public name may not have been set... 2021-10-15 13:48:26 -07:00
Sarah Jamie Lewis 2f14966051 For SetProfileAttribute to declar a proper zone 2021-10-15 13:48:26 -07:00
Sarah Jamie Lewis d54567339d Convert to new ScopedZone Interface 2021-10-15 13:48:26 -07:00
Dan Ballard fcc9d7148a Merge pull request 'Upgrade Cwtch' (#32) from cwtch-v1.11.1 into trunk
continuous-integration/drone/push Build is passing Details
Reviewed-on: #32
2021-09-30 23:08:59 +00:00
Sarah Jamie Lewis 585f1eed46 Always use path/filepath
continuous-integration/drone/pr Build is passing Details
2021-09-30 16:05:12 -07:00
Sarah Jamie Lewis 2f943d4b97 Upgrade Cwtch to 11.2 2021-09-30 16:03:53 -07:00
22 changed files with 2293 additions and 1398 deletions

View File

@ -1,39 +1,40 @@
---
kind: pipeline
type: docker
name: default
name: linux-android-windows-test
steps:
- name: fetch
image: golang
image: golang:1.19.1
volumes:
- name: deps
path: /go
commands:
- go install honnef.co/go/tools/cmd/staticcheck@latest
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/torrc
- chmod a+x tor
- go get -u golang.org/x/lint/golint
- git fetch --tags
#- export GO111MODULE=on
#- go mod vendor
- go get
- go mod download
# mobile is... special
# go get golang.org/x/mobile/bind
# TODO: upgrade to go1.16, remove mod/vendor, add go install for 1.16
- echo `git describe --tags` > VERSION
- echo `date +%G-%m-%d-%H-%M` > BUILDDATE
- name: quality
image: golang
image: golang:1.19.1
volumes:
- name: deps
path: /go
commands:
- go list ./... | xargs go vet
- go list ./... | xargs golint
- staticcheck ./...
#Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting
- name: build-linux
image: golang
image: golang:1.19.1
volumes:
- name: deps
path: /go
@ -41,7 +42,7 @@ steps:
- make linux
- name: build-android
image: openpriv/android-go-mobile:2021.03
image: openpriv/android-go-mobile:2023.02
volumes:
- name: deps
path: /go
@ -51,7 +52,7 @@ steps:
- make android
- name: build-windows
image: openpriv/mingw-go:2021.03
image: openpriv/mingw-go:2023.01
environment:
GOPATH: /go
volumes:
@ -62,6 +63,7 @@ steps:
- name: deploy-buildfiles
image: kroniak/ssh-client
pull: if-not-exists
environment:
BUILDFILES_KEY:
from_secret: buildfiles_key
@ -75,7 +77,7 @@ steps:
- echo $BUILDFILES_KEY > ~/id_rsab64
- base64 -d ~/id_rsab64 > ~/id_rsa
- chmod 400 ~/id_rsa
- export DIR=libCwtch-go-`cat VERSION`-`cat BUILDDATE`
- export DIR=libCwtch-go-`cat BUILDDATE`-`cat VERSION`
- mkdir $DIR
- mv libCwtch.so libCwtch.dll cwtch.aar cwtch-sources.jar libCwtch.h $DIR/
- cd $DIR
@ -86,6 +88,7 @@ steps:
- name: gitea-release
image: plugins/gitea-release
pull: if-not-exists
when:
event: tag
settings:
@ -102,18 +105,9 @@ steps:
- sha256
- sha512
- name: notify-email
image: drillster/drone-email
settings:
host: build.openprivacy.ca
port: 25
skip_verify: true
from: drone@openprivacy.ca
when:
status: [ failure ]
- name: notify-gogs
image: openpriv/drone-gogs
pull: if-not-exists
when:
event: pull_request
status: [ success, changed, failure ]
@ -135,3 +129,62 @@ trigger:
- push
- pull_request
- tag
---
kind: pipeline
type: exec
name: macos
platform:
os: darwin
arch: amd64
steps:
- name: fetch
commands:
- export PATH=$PATH:/usr/local/go/bin/
- git fetch --tags
- go get
# TODO: upgrade to go1.16, remove mod/vendor, add go install for 1.16
- echo `git describe --tags` > VERSION
- echo `date +%G-%m-%d-%H-%M` > BUILDDATE
- name: build-macos-x64
commands:
- export PATH=$PATH:/usr/local/go/bin/
- make libCwtch.x64.dylib
- name: build-macos-arm64
when:
event:
- push
status: [ success ]
commands:
- export PATH=$PATH:/usr/local/go/bin/
- make libCwtch.arm64.dylib
- name: deploy-buildfiles
environment:
BUILDFILES_KEY:
from_secret: buildfiles_key
when:
event:
- push
status: [ success ]
commands:
- echo $BUILDFILES_KEY > ~/id_rsab64
- base64 -d ~/id_rsab64 > ~/id_rsa
- chmod 400 ~/id_rsa
- export DIR=libCwtch-go-macos-`cat BUILDDATE`-`cat VERSION`
- mkdir $DIR
- mv libCwtch.x64.dylib $DIR/
- mv libCwtch.arm64.dylib $DIR/
- cd $DIR
- find . -type f -exec shasum -a 512 {} \; > ./../sha512s.txt
- mv ./../sha512s.txt .
- cd ..
- scp -r -o StrictHostKeyChecking=no -i ~/id_rsa $DIR buildfiles@build.openprivacy.ca:/home/buildfiles/buildfiles/
trigger:
repo: cwtch.im/libcwtch-go
branch: trunk
event:
- push
- pull_request

View File

@ -8,7 +8,7 @@ all: linux android windows
linux: libCwtch.so
macos: libCwtch.dylib
macos: libCwtch.x64.dylib libCwtch.arm64.dylib
android: cwtch.aar
@ -16,19 +16,27 @@ windows: libCwtch.dll
libCwtch.so: lib.go
./switch-ffi.sh
go build -buildmode c-shared -o libCwtch.so
go build -trimpath -ldflags "-buildid=$(shell git describe --tags) -X main.buildVer=$(shell git describe --tags) -X main.buildDate=$(shell git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M)" -buildmode c-shared -o libCwtch.so
libCwtch.dylib: lib.go
libCwtch.x64.dylib: lib.go
./switch-ffi.sh
go build -buildmode c-shared -o libCwtch.dylib
go build -trimpath -ldflags "-buildid=$(shell git describe --tags) -X main.buildVer=$(shell git describe --tags) -X main.buildDate=$(shell git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M)" -buildmode c-shared -o libCwtch.x64.dylib
libCwtch.arm64.dylib: lib.go
./switch-ffi.sh
env GOARCH=arm64 GOOS=darwin CGO_ENABLED=1 go build -trimpath -ldflags "-buildid=$(shell git describe --tags) -X main.buildVer=$(shell git describe --tags) -X main.buildDate=$(shell git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M)" -buildmode c-shared -o libCwtch.arm64.dylib
cwtch.aar: lib.go
./switch-gomobile.sh
gomobile bind -target android
gomobile bind -trimpath -target android/arm,android/arm64,android/amd64 -ldflags="-buildid=$(shell git describe --tags) -X cwtch.buildVer=$(shell git describe --tags) -X cwtch.buildDate=$(shell git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M)"
libCwtch.dll: lib.go
./switch-ffi.sh
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc-win32 go build -buildmode c-shared -o libCwtch.dll
# '-Xlinker --no-insert-timestamp` sets the output dll PE timestamp header to all zeros, instead of the actual time
# this is necessary for reproducible builds (see: https://wiki.debian.org/ReproducibleBuilds/TimestampsInPEBinaries for additional information)
# note: the above documentation also references an ability to set an optional timestamp - this behaviour seems to no longer be supported in more recent versions of mingw32-gcc (the help docs no longer reference that functionality)
# these flags have to be passed through to the underlying gcc process using the -extldflags option in the underlying go linker, note that the whole flag is quoted...this is necessary.
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc-win32 go build -trimpath -ldflags "-buildid=$(shell git describe --tags) -X main.buildVer=$(shell git describe --tags) -X main.buildDate=$(shell git log -1 --format=%cd --date=format:%G-%m-%d-%H-%M) '-extldflags=-Xlinker --no-insert-timestamp'" -buildmode c-shared -o libCwtch.dll
clean:
rm -f cwtch.aar cwtch_go.apk libCwtch.h libCwtch.so cwtch-sources.jar libCwtch.dll libCwtch.dylib

View File

@ -1,3 +1,5 @@
# NOTE: libcwtch-go has been deprecated in favour of [autobindings](https://git.openprivacy.ca/cwtch.im/autobindings). This repository has been archived and is no longer maintained.
# libcwtch-go
C-bindings for the Go Cwtch Library.
@ -6,12 +8,35 @@ C-bindings for the Go Cwtch Library.
make linux
make android
make windows
make macos
## Android Build Notes
Our build infrastructure is using Go 1.15.10, NDK 21.0.6113669,
and gomobile commit bdb1ca9a1e083af5929a8214e8a056d638ebbf2d (2021 07 16)
Go 1.17.4, NDK 22.1.7171670, and gomobile 4e6c2922fdeed32d3596616518aaee7b0d79ce55 (2021 12 07) appear to compile as well.
Other version combinations untested and some definitely do not work.
## Windows
Cwtch relies on sqlite which in turn requires the use of CGO. As per [this issue](https://github.com/golang/go/issues/12029)
that means [TDM-GCC](https://jmeubank.github.io/tdm-gcc/download/) is required to be installed and used to compile on Windows.
Install it and add it to your path and `make windows` should then work.
## Experimental iOS support
make ios
# Using
## General Environment Variables
- `LOG_FILE` if defined will mean all go logging will go to a file instead of stdout
- `LOG_LEVEL` if set to `debug` will cause debug logging to be included in log output
- `CWTCH_PROFILE` if set to `1` will cause a memory profile to be written to `mem.prof` and all active goroutines
written to `stdout` when `DebugInfo()` is called.
## Linux Desktop:
- `LD_LIBRARY_PATH` set to point to `libCwtch.so`
@ -24,3 +49,7 @@ C-bindings for the Go Cwtch Library.
## Windows
- copy libCwtch.dll into the directory of the `.exe` using it
## MacOS
- copy libCwtch.x64.dylib and libCwtch.arm.dylib into the directory you are executing from

View File

@ -5,8 +5,10 @@ const SchemaVersion = "schemaVersion"
const Name = "name"
const LastRead = "last-read"
const Picture = "picture"
const DefaultProfilePicture = "defaultPicture"
const ShowBlocked = "show-blocked"
const Archived = "archived"
const LastSeenTime = "lastMessageSeenTime"
const ProfileTypeV1DefaultPassword = "v1-defaultPassword"
const ProfileTypeV1Password = "v1-userPassword"
@ -14,6 +16,14 @@ const ProfileTypeV1Password = "v1-userPassword"
// PeerOnline stores state on if the peer believes it is online
const PeerOnline = "peer-online"
const PeerAutostart = "autostart"
// Description is used on server contacts,
const Description = "description"
// ConversationNotificationPolicy is the attribute label for conversations. When App NotificationPolicy is OptIn a true value here opts in
const ConversationNotificationPolicy = "notification-policy"
const StateProfilePane = "state-profile-pane"
const StateSelectedConversation = "state-selected-conversation"
const StateSelectedProfileTime = "state-selected-profile-time"
@ -22,3 +32,6 @@ const StateSelectedProfileTime = "state-selected-profile-time"
const BlockUnknownPeersSetting = "blockunknownpeers"
const LocaleSetting = "locale"
const ZoomSetting = "zoom"
// App Experiments
const MessageFormattingExperiment = "message-formatting"

View File

@ -2,4 +2,34 @@ package constants
// We offer "un-passworded" profiles but our storage encrypts everything with a password. We need an agreed upon
// password to use in that case, that the app case use behind the scenes to password and unlock with
// https://docs.openprivacy.ca/cwtch-security-handbook/profile_encryption_and_storage.html
const DefactoPasswordForUnencryptedProfiles = "be gay do crime"
const (
// StatusSuccess is an event response for event.Status signifying a call succeeded
StatusSuccess = "success"
// StatusError is an event response for event.Status signifying a call failed in error, ideally accompanied by a event.Error
StatusError = "error"
)
type NotificationType string
const (
// NotificationNone enum for message["notification"] that means no notification
NotificationNone = NotificationType("None")
// NotificationEvent enum for message["notification"] that means emit a notification that a message event happened only
NotificationEvent = NotificationType("SimpleEvent")
// NotificationConversation enum for message["notification"] that means emit a notification event with Conversation handle included
NotificationConversation = NotificationType("ContactInfo")
)
const (
// ConversationNotificationPolicyDefault enum for conversations indicating to use global notification policy
ConversationNotificationPolicyDefault = "ConversationNotificationPolicy.Default"
// ConversationNotificationPolicyOptIn enum for conversation indicating to opt in to nofitications when allowed
ConversationNotificationPolicyOptIn = "ConversationNotificationPolicy.OptIn"
// ConversationNotificationPolicyNever enum for conversation indicating to opt in to never do notifications
ConversationNotificationPolicyNever = "ConversationNotificationPolicy.Never"
)
const DartIso8601 = "2006-01-02T15:04:05.999Z"

View File

@ -1,26 +0,0 @@
package constants
import "cwtch.im/cwtch/event"
// The server manager defines its own events, most should be self-explanatory:
const (
NewServer = event.Type("NewServer")
// Force a UI update
ListServers = event.Type("ListServers")
// Takes an Onion, used to toggle off/on Server availability
StartServer = event.Type("StartServer")
StopServer = event.Type("StopServer")
// Takes an Onion and a AutoStartEnabled boolean
AutoStart = event.Type("AutoStart")
// Get the status of a particular server (takes an Onion)
CheckServerStatus = event.Type("CheckServerStatus")
ServerStatusUpdate = event.Type("ServerStatusUpdate")
)
const (
AutoStartEnabled = event.Field("AutoStartEnabled")
)

View File

@ -1,41 +0,0 @@
package contact
import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer"
"git.openprivacy.ca/cwtch.im/libcwtch-go/features"
"git.openprivacy.ca/openprivacy/connectivity/tor"
)
// Functionality groups some common UI triggered functions for contacts...
type Functionality struct {
}
const addContactPrefix = "addcontact"
const sendMessagePrefix = "sendmessage"
// FunctionalityGate returns contact.Functionality always
func FunctionalityGate(experimentMap map[string]bool) (*Functionality, error) {
return new(Functionality), nil
}
// SendMessage handles sending messages to contacts
func (pf *Functionality) SendMessage(peer peer.SendMessages, handle string, message string) features.Response {
eventID := peer.SendMessageToPeer(handle, message)
return features.ConstructResponse(sendMessagePrefix, eventID)
}
// HandleImportString handles contact import strings
func (pf *Functionality) HandleImportString(peer peer.ModifyContactsAndPeers, importString string) features.Response {
if tor.IsValidHostname(importString) {
if peer.GetContact(importString) == nil {
peer.AddContact(importString, importString, model.AuthApproved)
// Implicit Peer Attempt
peer.PeerWithOnion(importString)
return features.ConstructResponse(addContactPrefix, "success")
}
return features.ConstructResponse(addContactPrefix, "contact_already_exists")
}
return features.ConstructResponse(addContactPrefix, "invalid_import_string")
}

View File

@ -1,124 +0,0 @@
package contact
import (
"cwtch.im/cwtch/model"
"git.openprivacy.ca/cwtch.im/libcwtch-go/features"
"testing"
)
const ValidHostname = "openpravyvc6spbd4flzn4g2iqu4sxzsizbtb5aqec25t76dnoo5w7yd"
type MockPeer struct {
hasContact bool
addContact bool
peerRequest bool
}
func (m MockPeer) BlockUnknownConnections() {
panic("should never be called")
}
func (m MockPeer) AllowUnknownConnections() {
panic("should never be called")
}
func (m MockPeer) GetContacts() []string {
panic("should never be called")
}
func (m MockPeer) GetContact(s string) *model.PublicProfile {
if m.hasContact {
return &(model.GenerateNewProfile("").PublicProfile)
}
return nil
}
func (m MockPeer) GetContactAttribute(s string, s2 string) (string, bool) {
panic("should never be called")
}
func (m *MockPeer) AddContact(nick, onion string, authorization model.Authorization) {
m.addContact = true
}
func (m MockPeer) SetContactAuthorization(s string, authorization model.Authorization) error {
panic("should never be called")
}
func (m MockPeer) SetContactAttribute(s string, s2 string, s3 string) {
panic("should never be called")
}
func (m MockPeer) DeleteContact(s string) {
panic("should never be called")
}
func (m *MockPeer) PeerWithOnion(s string) {
m.peerRequest = true
}
func (m MockPeer) JoinServer(s string) error {
panic("should never be called")
}
func TestContactFunctionality_InValidHostname(t *testing.T) {
cf, _ := FunctionalityGate(map[string]bool{})
peer := &MockPeer{
hasContact: false,
addContact: false,
peerRequest: false,
}
response := cf.HandleImportString(peer, "")
if peer.addContact || peer.peerRequest {
t.Fatalf("HandleImportString for a malformed import string should have no resulted in addContact or a peerRequest: %v", peer)
}
if response.Error() != features.ConstructResponse(addContactPrefix, "invalid_import_string").Error() {
t.Fatalf("Response to a successful import is malformed: %v", response)
}
}
func TestContactFunctionality_ValidHostnameExistingContact(t *testing.T) {
cf, _ := FunctionalityGate(map[string]bool{})
peer := &MockPeer{
hasContact: true,
addContact: false,
peerRequest: false,
}
response := cf.HandleImportString(peer, ValidHostname)
if peer.addContact || peer.peerRequest {
t.Fatalf("HandleImportString for a valid string should not call addContact or a peerRequest when the contact already exists: %v", peer)
}
if response.Error() != features.ConstructResponse(addContactPrefix, "contact_already_exists").Error() {
t.Fatalf("Response to a successful import is malformed: %v", response)
}
}
func TestContactFunctionality_ValidHostnameUnknownContact(t *testing.T) {
cf, _ := FunctionalityGate(map[string]bool{})
peer := &MockPeer{
hasContact: false,
addContact: false,
peerRequest: false,
}
response := cf.HandleImportString(peer, ValidHostname)
if peer.addContact && peer.peerRequest {
if response.Error() != features.ConstructResponse(addContactPrefix, "success").Error() {
t.Fatalf("Response to a successful import is malformed: %v", response)
}
} else {
t.Fatalf("HandleImportString for a valid import string should have resulted in addContact or a peerRequest: %v", peer)
}
}

View File

@ -3,21 +3,16 @@ package groups
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
constants2 "cwtch.im/cwtch/model/constants"
"cwtch.im/cwtch/peer"
"encoding/base64"
"cwtch.im/cwtch/protocol/connections"
"fmt"
"git.openprivacy.ca/cwtch.im/libcwtch-go/features"
"git.openprivacy.ca/openprivacy/log"
"strings"
"git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
)
const serverPrefix = "server:"
const tofuBundlePrefix = "tofubundle:"
const groupPrefix = "torv3"
const groupExperiment = "tapir-groups-experiment"
const importBundlePrefix = "importBundle"
const (
// ServerList is a json encoded list of servers
ServerList = event.Field("ServerList")
@ -28,12 +23,6 @@ const (
UpdateServerInfo = event.Type("UpdateServerInfo")
)
// ReadServerInfo is a meta-interface for reading information about servers..
type ReadServerInfo interface {
peer.ReadContacts
peer.ReadServers
}
// GroupFunctionality provides experiment gated server functionality
type GroupFunctionality struct {
}
@ -46,27 +35,8 @@ func ExperimentGate(experimentMap map[string]bool) (*GroupFunctionality, error)
return nil, fmt.Errorf("gated by %v", groupExperiment)
}
// SendMessage is a deprecated api
func (gf *GroupFunctionality) SendMessage(peer peer.CwtchPeer, handle string, message string) (string, error) {
// TODO this auto accepting behaviour needs some thinking through
if !peer.GetGroup(handle).Accepted {
err := peer.AcceptInvite(handle)
if err != nil {
log.Errorf("tried to mark a nonexistent group as existed. bad!")
return "", err
}
}
return peer.SendMessageToGroupTracked(handle, message)
}
// ValidPrefix returns true if an import string contains a prefix that indicates it contains information about a
// server or a group
func (gf *GroupFunctionality) ValidPrefix(importString string) bool {
return strings.HasPrefix(importString, tofuBundlePrefix) || strings.HasPrefix(importString, serverPrefix) || strings.HasPrefix(importString, groupPrefix)
}
// GetServerInfoList compiles all the information the UI might need regarding all servers..
func (gf *GroupFunctionality) GetServerInfoList(profile ReadServerInfo) []Server {
func (gf *GroupFunctionality) GetServerInfoList(profile peer.CwtchPeer) []Server {
var servers []Server
for _, server := range profile.GetServers() {
servers = append(servers, gf.GetServerInfo(server, profile))
@ -76,52 +46,21 @@ func (gf *GroupFunctionality) GetServerInfoList(profile ReadServerInfo) []Server
// GetServerInfo compiles all the information the UI might need regarding a particular server including any verified
// cryptographic keys
func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.ReadContacts) Server {
serverInfo := profile.GetContact(serverOnion)
func (gf *GroupFunctionality) GetServerInfo(serverOnion string, profile peer.CwtchPeer) Server {
serverInfo, _ := profile.FetchConversationInfo(serverOnion)
keyTypes := []model.KeyType{model.KeyTypeServerOnion, model.KeyTypeTokenOnion, model.KeyTypePrivacyPass}
var serverKeys []ServerKey
for _, keyType := range keyTypes {
if key, has := serverInfo.GetAttribute(string(keyType)); has {
if key, has := serverInfo.GetAttribute(attr.PublicScope, attr.ServerKeyZone, string(keyType)); has {
serverKeys = append(serverKeys, ServerKey{Type: string(keyType), Key: key})
}
}
return Server{Onion: serverOnion, Status: serverInfo.State, Keys: serverKeys}
}
// HandleImportString handles import strings for groups and servers
func (gf *GroupFunctionality) HandleImportString(peer peer.CwtchPeer, importString string) error {
if strings.HasPrefix(importString, tofuBundlePrefix) {
bundle := strings.Split(importString, "||")
if len(bundle) == 2 {
err := gf.HandleImportString(peer, bundle[0][len(tofuBundlePrefix):])
// if the server import failed then abort the whole process..
if !strings.HasSuffix(err.Error(), "success") {
return features.ConstructResponse(importBundlePrefix, err.Error())
}
return gf.HandleImportString(peer, bundle[1])
}
} else if strings.HasPrefix(importString, serverPrefix) {
// Server Key Bundles are prefixed with
bundle, err := base64.StdEncoding.DecodeString(importString[len(serverPrefix):])
if err == nil {
if err = peer.AddServer(string(bundle)); err != nil {
return features.ConstructResponse(importBundlePrefix, err.Error())
}
return features.ConstructResponse(importBundlePrefix, "success")
}
return features.ConstructResponse(importBundlePrefix, err.Error())
} else if strings.HasPrefix(importString, groupPrefix) {
//eg: torv3JFDWkXExBsZLkjvfkkuAxHsiLGZBk0bvoeJID9ItYnU=EsEBCiBhOWJhZDU1OTQ0NWI3YmM2N2YxYTM5YjkzMTNmNTczNRIgpHeNaG+6jy750eDhwLO39UX4f2xs0irK/M3P6mDSYQIaOTJjM2ttb29ibnlnaGoyenc2cHd2N2Q1N3l6bGQ3NTNhdW8zdWdhdWV6enB2ZmFrM2FoYzRiZHlkCiJAdVSSVgsksceIfHe41OJu9ZFHO8Kwv3G6F5OK3Hw4qZ6hn6SiZjtmJlJezoBH0voZlCahOU7jCOg+dsENndZxAA==
if gid, err := peer.ImportGroup(importString); err != nil {
return features.ConstructResponse(importBundlePrefix, err.Error())
} else {
// Auto accept the group here.
if peer.AcceptInvite(gid) != nil {
log.Errorf("Error accepting invite: %v", err)
}
return features.ConstructResponse(importBundlePrefix, "success")
}
}
return features.ConstructResponse(importBundlePrefix, "invalid_group_invite_prefix")
description, _ := serverInfo.GetAttribute(attr.LocalScope, attr.ServerZone, constants.Description)
startTimeStr := serverInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants2.SyncPreLastMessageTime)).ToString()]
recentTimeStr := serverInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants2.SyncMostRecentMessageTime)).ToString()]
syncStatus := SyncStatus{startTimeStr, recentTimeStr}
return Server{Onion: serverOnion, Identifier: serverInfo.ID, Status: connections.ConnectionStateName[profile.GetPeerState(serverInfo.Handle)], Keys: serverKeys, Description: description, SyncProgress: syncStatus}
}

View File

@ -2,22 +2,6 @@ package groups
import "testing"
func TestGroupFunctionality_ValidPrefix(t *testing.T) {
gf, _ := ExperimentGate(map[string]bool{groupExperiment: true})
if gf.ValidPrefix("torv3blahblahblah") == false {
t.Fatalf("torv3 should be a valid prefix")
}
if gf.ValidPrefix("tofubundle:32432423||3242342") == false {
t.Fatalf("tofubundle should be a valid prefix")
}
if gf.ValidPrefix("server:23541233t") == false {
t.Fatalf("server should be a valid prefix")
}
if gf.ValidPrefix("alice!24234") == true {
t.Fatalf("alice should be an invalid predix")
}
}
func TestGroupFunctionality_IsEnabled(t *testing.T) {
_, err := ExperimentGate(map[string]bool{})

View File

@ -5,8 +5,16 @@ type ServerKey struct {
Key string `json:"key"`
}
type Server struct {
Onion string `json:"onion"`
Status string `json:"status"`
Keys []ServerKey `json:"keys"`
type SyncStatus struct {
StartTime string `json:"startTime"`
LastMessageTime string `json:"lastMessageTime"`
}
type Server struct {
Onion string `json:"onion"`
Identifier int `json:"identifier"`
Status string `json:"status"`
Description string `json:"description"`
Keys []ServerKey `json:"keys"`
SyncProgress SyncStatus `json:"syncProgress"`
}

View File

@ -0,0 +1,220 @@
package servers
import (
"cwtch.im/cwtch/event"
"fmt"
"git.openprivacy.ca/cwtch.im/server"
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/log"
"os"
"path/filepath"
"strconv"
"sync"
"time"
)
const serversExperiment = "servers-experiment"
const (
ZeroServersLoaded = event.Type("ZeroServersLoaded")
NewServer = event.Type("NewServer")
ServerIntentUpdate = event.Type("ServerIntentUpdate")
ServerDeleted = event.Type("ServerDeleted")
ServerStatsUpdate = event.Type("ServerStatsUpdate")
)
const (
Intent = event.Field("Intent")
TotalMessages = event.Field("TotalMessages")
Connections = event.Field("Connections")
)
const (
IntentRunning = "running"
IntentStopped = "stopped"
)
// TODO: move into Cwtch model/attr
type ServerInfo struct {
Onion string
ServerBundle string
Autostart bool
Running bool
Description string
StorageType string
}
type PublishFn func(event.Event)
var lock sync.Mutex
var appServers server.Servers
var publishFn PublishFn
var killStatsUpdate chan bool = make(chan bool, 1)
var enabled bool = false
func InitServers(acn connectivity.ACN, appdir string, pfn PublishFn) {
lock.Lock()
defer lock.Unlock()
if appServers == nil {
serversDir := filepath.Join(appdir, "servers")
err := os.MkdirAll(serversDir, 0700)
if err != nil {
log.Errorf("Could not init servers directory: %s", err)
}
appServers = server.NewServers(acn, serversDir)
publishFn = pfn
}
}
func Disable() {
lock.Lock()
defer lock.Unlock()
if appServers != nil {
appServers.Stop()
}
if enabled {
enabled = false
killStatsUpdate <- true
}
}
func Enabled() bool {
lock.Lock()
defer lock.Unlock()
return enabled
}
// ServersFunctionality provides experiment gated server functionality
type ServersFunctionality struct {
}
// ExperimentGate returns ServersFunctionality if the experiment is enabled, and an error otherwise.
func ExperimentGate(experimentMap map[string]bool) (*ServersFunctionality, error) {
if experimentMap[serversExperiment] {
lock.Lock()
defer lock.Unlock()
return &ServersFunctionality{}, nil
}
return nil, fmt.Errorf("gated by %v", serversExperiment)
}
func (sf *ServersFunctionality) Enable() {
lock.Lock()
defer lock.Unlock()
if appServers != nil && !enabled {
enabled = true
go cacheForwardServerMetricUpdates()
}
}
func (sf *ServersFunctionality) LoadServers(password string) ([]string, error) {
servers, err := appServers.LoadServers(password)
// server:1.3/libcwtch-go:1.4 accidentally enabled monitor logging by default. make sure it's turned off
for _, onion := range servers {
server := appServers.GetServer(onion)
server.SetMonitorLogging(false)
}
return servers, err
}
func (sf *ServersFunctionality) CreateServer(password string) (server.Server, error) {
return appServers.CreateServer(password)
}
func (sf *ServersFunctionality) GetServer(onion string) server.Server {
return appServers.GetServer(onion)
}
func (sf *ServersFunctionality) GetServerStatistics(onion string) server.Statistics {
s := appServers.GetServer(onion)
if s != nil {
return s.GetStatistics()
}
return server.Statistics{}
}
func (sf *ServersFunctionality) ListServers() []string {
return appServers.ListServers()
}
func (sf *ServersFunctionality) DeleteServer(onion string, currentPassword string) error {
return appServers.DeleteServer(onion, currentPassword)
}
func (sf *ServersFunctionality) LaunchServer(onion string) {
appServers.LaunchServer(onion)
server := appServers.GetServer(onion)
if server != nil {
newStats := server.GetStatistics()
publishFn(event.NewEventList(ServerStatsUpdate, event.Identity, onion, TotalMessages, strconv.Itoa(newStats.TotalMessages), Connections, strconv.Itoa(newStats.TotalConnections)))
}
}
func (sf *ServersFunctionality) StopServer(onion string) {
appServers.StopServer(onion)
}
func (sf *ServersFunctionality) DestroyServers() {
appServers.Destroy()
}
func (sf *ServersFunctionality) GetServerInfo(onion string) *ServerInfo {
s := sf.GetServer(onion)
var serverInfo ServerInfo
serverInfo.Onion = s.Onion()
serverInfo.ServerBundle = s.ServerBundle()
serverInfo.Autostart = s.GetAttribute(server.AttrAutostart) == "true"
running, _ := s.CheckStatus()
serverInfo.Running = running
serverInfo.Description = s.GetAttribute(server.AttrDescription)
serverInfo.StorageType = s.GetAttribute(server.AttrStorageType)
return &serverInfo
}
func (si *ServerInfo) EnrichEvent(e *event.Event) {
e.Data["Onion"] = si.Onion
e.Data["ServerBundle"] = si.ServerBundle
e.Data["Description"] = si.Description
e.Data["StorageType"] = si.StorageType
if si.Autostart {
e.Data["Autostart"] = "true"
} else {
e.Data["Autostart"] = "false"
}
if si.Running {
e.Data["Running"] = "true"
} else {
e.Data["Running"] = "false"
}
}
// cacheForwardServerMetricUpdates every minute gets metrics for all servers, and if they have changed, sends events to the UI
func cacheForwardServerMetricUpdates() {
var cache map[string]server.Statistics = make(map[string]server.Statistics)
duration := time.Second // allow first load
for {
select {
case <-time.After(duration):
duration = time.Minute
serverList := appServers.ListServers()
for _, serverOnion := range serverList {
server := appServers.GetServer(serverOnion)
if running, err := server.CheckStatus(); running && err == nil {
newStats := server.GetStatistics()
if stats, ok := cache[serverOnion]; !ok || stats.TotalConnections != newStats.TotalConnections || stats.TotalMessages != newStats.TotalMessages {
cache[serverOnion] = newStats
publishFn(event.NewEventList(ServerStatsUpdate, event.Identity, serverOnion, TotalMessages, strconv.Itoa(newStats.TotalMessages), Connections, strconv.Itoa(newStats.TotalConnections)))
}
}
}
case <-killStatsUpdate:
return
}
}
}
func Shutdown() {
Disable()
appServers.Destroy()
}

31
go.mod
View File

@ -1,12 +1,31 @@
module git.openprivacy.ca/cwtch.im/libcwtch-go
go 1.15
go 1.17
require (
cwtch.im/cwtch v0.11.1
git.openprivacy.ca/openprivacy/connectivity v1.5.0
cwtch.im/cwtch v0.18.10
git.openprivacy.ca/cwtch.im/server v1.4.5
git.openprivacy.ca/openprivacy/connectivity v1.8.6
git.openprivacy.ca/openprivacy/log v1.0.3
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect
golang.org/x/mod v0.5.0 // indirect
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
github.com/mutecomm/go-sqlcipher/v4 v4.4.2
)
require (
filippo.io/edwards25519 v1.0.0 // indirect
git.openprivacy.ca/cwtch.im/tapir v0.6.0 // indirect
git.openprivacy.ca/openprivacy/bine v0.0.4 // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.3-0.20210930101514-6bb39798585c // indirect
github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect
// go mobile should stay pinned to golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08
// until we intentionally upgrade it, requiring upgrading our docker container
// android_go_mobile as well (matching version there), and possibly after upgrading past go 1.17
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

202
go.sum
View File

@ -1,100 +1,202 @@
cwtch.im/cwtch v0.11.0 h1:CwmbaMEbL0lOiPagfWxA7po2HSq49B1lcFjPB7UR8k4=
cwtch.im/cwtch v0.11.0/go.mod h1:QpTkQK7MqNt0dQK9/pBk5VpkvFhy6xuoxJIn401B8fM=
cwtch.im/cwtch v0.11.1 h1:9HHcGwij3WIt53ZuKQUSqQ4x29CnZJ7TufA+t+cat/M=
cwtch.im/cwtch v0.11.1/go.mod h1:QpTkQK7MqNt0dQK9/pBk5VpkvFhy6xuoxJIn401B8fM=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
cwtch.im/cwtch v0.18.0/go.mod h1:StheazFFY7PKqBbEyDVLhzWW6WOat41zV0ckC240c5Y=
cwtch.im/cwtch v0.18.3 h1:3zBvC4buII6pWQ+OOVUR6WuAwQDKCxSrj0ZOYKEeB6I=
cwtch.im/cwtch v0.18.3/go.mod h1:StheazFFY7PKqBbEyDVLhzWW6WOat41zV0ckC240c5Y=
cwtch.im/cwtch v0.18.4 h1:Oht7rEDVJjVWDOKg0xqDgXvY/H059HMJlOPt/nBGqxk=
cwtch.im/cwtch v0.18.4/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
cwtch.im/cwtch v0.18.5 h1:yqDns4flbowsbaWjMiUm7Em4IAlM8kkgm79CCcXV1GE=
cwtch.im/cwtch v0.18.5/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
cwtch.im/cwtch v0.18.6 h1:CRwoZ/H7y1rAp6jrYh6YCIILU+Sw59hJUvHaWqPgBjg=
cwtch.im/cwtch v0.18.6/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
cwtch.im/cwtch v0.18.7 h1:ysE1kjy4oTF+VaQrkNdwdEs6rklWGOe9Dp8rlu9VDKI=
cwtch.im/cwtch v0.18.7/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
cwtch.im/cwtch v0.18.8 h1:D5mmsBkmHhE7jhRodZG2DtdaxmfvdvLG0W7CAPBf7eo=
cwtch.im/cwtch v0.18.8/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
cwtch.im/cwtch v0.18.10 h1:iTzLzlms1mgn8kLfClU/yAWIVWVRRT8UmfbDNli9dzE=
cwtch.im/cwtch v0.18.10/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.openprivacy.ca/cwtch.im/tapir v0.4.9 h1:LXonlztwvI1F1++0IyomIcDH1/Bxzo+oN8YjGonNvjM=
git.openprivacy.ca/cwtch.im/tapir v0.4.9/go.mod h1:p4bHo3DAO8wwimU6JAeZXbfPQ4jnoA2bV+4YvknWTNQ=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.openprivacy.ca/cwtch.im/server v1.4.5 h1:QuNAIxld+aWeQfWuGHB2QYZXsqJMmTyl55Pcmdn8FQA=
git.openprivacy.ca/cwtch.im/server v1.4.5/go.mod h1:dGB1bePUgDU9xwk7gGkioNeshrbNgGWhSH8zMQwIAUg=
git.openprivacy.ca/cwtch.im/tapir v0.5.5 h1:km6UDrLYH/GCEn2s+S299/TiRHhxKCIAipYr9GbG3Hk=
git.openprivacy.ca/cwtch.im/tapir v0.5.5/go.mod h1:bWWHrDYBtHvxMri59RwIB/w7Eg1aC0BrQ/ycKlnbB5k=
git.openprivacy.ca/cwtch.im/tapir v0.6.0 h1:TtnKjxitkIDMM7Qn0n/u+mOHRLJzuQUYjYRu5n0/QFY=
git.openprivacy.ca/cwtch.im/tapir v0.6.0/go.mod h1:iQIq4y7N+DuP3CxyG66WNEC/d6vzh+wXvvOmelB+KoY=
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
git.openprivacy.ca/openprivacy/connectivity v1.5.0 h1:ZxsR/ZaVKXIkD2x6FlajZn62ciNQjamrI4i/5xIpdoQ=
git.openprivacy.ca/openprivacy/connectivity v1.5.0/go.mod h1:UjQiGBnWbotmBzIw59B8H6efwDadjkKzm3RPT1UaIRw=
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
git.openprivacy.ca/openprivacy/connectivity v1.8.6 h1:g74PyDGvpMZ3+K0dXy3mlTJh+e0rcwNk0XF8owzkmOA=
git.openprivacy.ca/openprivacy/connectivity v1.8.6/go.mod h1:Hn1gpOx/bRZp5wvCtPQVJPXrfeUH0EGiG/Aoa0vjGLg=
git.openprivacy.ca/openprivacy/log v1.0.3 h1:E/PMm4LY+Q9s3aDpfySfEDq/vYQontlvNj/scrPaga0=
git.openprivacy.ca/openprivacy/log v1.0.3/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/gtank/ristretto255 v0.1.3-0.20210930101514-6bb39798585c h1:gkfmnY4Rlt3VINCo4uKdpvngiibQyoENVj5Q88sxXhE=
github.com/gtank/ristretto255 v0.1.3-0.20210930101514-6bb39798585c/go.mod h1:tDPFhGdt3hJWqtKwx57i9baiB1Cj0yAg22VOPUqm5vY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b h1:QrHweqAtyJ9EwCaGHBu1fghwxIPiopAHV06JlXrMHjk=
github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b/go.mod h1:xxLb2ip6sSUts3g1irPVHyk/DGslwQsNOo9I7smJfNU=
github.com/mutecomm/go-sqlcipher/v4 v4.4.2 h1:eM10bFtI4UvibIsKr10/QT7Yfz+NADfjZYh0GKrXUNc=
github.com/mutecomm/go-sqlcipher/v4 v4.4.2/go.mod h1:mF2UmIpBnzFeBdu/ypTDb/LdbS0nk0dfSN1WUsWTjMA=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 h1:3In5TnfvnuXTF/uflgpYxSCEGP2NdYT37KsPh3VjZYU=
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 h1:3vUV5x5+3LfQbgk7paCM6INOaJG9xXQbn79xoNkwfIk=
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

1436
lib.go

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ go list ./... | xargs go vet
echo ""
echo "Linting:"
go list ./... | xargs golint
staticcheck ./...
echo "Time to format"
@ -21,4 +21,4 @@ ineffassign .
# misspell (https://github.com/client9/misspell/cmd/misspell)
echo "Checking for misspelled words..."
misspell . | grep -v "vendor/" | grep -v "go.sum" | grep -v ".idea"
misspell . | grep -v "testing/" | grep -v "vendor/" | grep -v "go.sum" | grep -v ".idea"

View File

@ -1,16 +1,25 @@
package utils
import "cwtch.im/cwtch/model"
type Contact struct {
Name string `json:"name"`
Onion string `json:"onion"`
Status string `json:"status"`
Picture string `json:"picture"`
Authorization string `json:"authorization"`
SaveHistory string `json:"saveConversationHistory"`
Messages int `json:"numMessages"`
Unread int `json:"numUnread"`
LastMessage string `json:"lastMsgTime"`
IsGroup bool `json:"isGroup"`
GroupServer string `json:"groupServer"`
IsArchived bool `json:"isArchived"`
Name string `json:"name"`
Onion string `json:"onion"`
Status string `json:"status"`
Picture string `json:"picture"`
DefaultPicture string `json:"defaultPicture"`
Accepted bool `json:"accepted"`
AccessControlList model.AccessControlList `json:"accessControlList"`
Blocked bool `json:"blocked"`
SaveHistory string `json:"saveConversationHistory"`
Messages int `json:"numMessages"`
Unread int `json:"numUnread"`
LastSeenMessageId int `json:"lastSeenMessageId"`
LastMessage string `json:"lastMsgTime"`
IsGroup bool `json:"isGroup"`
GroupServer string `json:"groupServer"`
IsArchived bool `json:"isArchived"`
Identifier int `json:"identifier"`
NotificationPolicy string `json:"notificationPolicy"`
Attributes map[string]string `json:"attributes"`
}

View File

@ -1,41 +1,54 @@
package utils
import (
"encoding/json"
"fmt"
"git.openprivacy.ca/cwtch.im/libcwtch-go/features/servers"
"os"
"strconv"
"cwtch.im/cwtch/app"
"cwtch.im/cwtch/app/plugins"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"cwtch.im/cwtch/model/constants"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/protocol/connections"
"encoding/json"
"git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
constants2 "git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
"git.openprivacy.ca/cwtch.im/libcwtch-go/features/groups"
"git.openprivacy.ca/openprivacy/log"
"strconv"
"time"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/functionality/filesharing"
)
import "cwtch.im/cwtch/event"
type EventProfileEnvelope struct {
Event event.Event
Profile string
}
type LCG_API_Handler struct {
LaunchServers func()
StopServers func()
}
type EventHandler struct {
app app.Application
appBusQueue event.Queue
profileEvents chan EventProfileEnvelope
api LCG_API_Handler
}
func NewEventHandler() *EventHandler {
eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileEvents: make(chan EventProfileEnvelope)}
// We should be reading from profile events pretty quickly, but we make this buffer fairly large...
const profileEventsBufferSize = 512
func NewEventHandler(api LCG_API_Handler) *EventHandler {
eh := &EventHandler{app: nil, appBusQueue: event.NewQueue(), profileEvents: make(chan EventProfileEnvelope, profileEventsBufferSize), api: api}
return eh
}
// PublishAppEvent is a way for libCwtch-go to publish an event for consumption by a UI before a Cwtch app has been initialized
// Main use: to signal an error before a cwtch app could be created
func (eh *EventHandler) PublishAppEvent(event event.Event) {
eh.appBusQueue.Publish(event)
}
func (eh *EventHandler) HandleApp(application app.Application) {
eh.app = application
application.GetPrimaryBus().Subscribe(event.NewPeer, eh.appBusQueue)
@ -44,10 +57,15 @@ func (eh *EventHandler) HandleApp(application app.Application) {
application.GetPrimaryBus().Subscribe(event.Shutdown, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.AppError, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNStatus, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ReloadDone, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.ACNVersion, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(UpdateGlobalSettings, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(CwtchStarted, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(servers.NewServer, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(servers.ServerIntentUpdate, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(servers.ServerDeleted, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(servers.ServerStatsUpdate, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.StartingStorageMiragtion, eh.appBusQueue)
application.GetPrimaryBus().Subscribe(event.DoneStorageMigration, eh.appBusQueue)
}
func (eh *EventHandler) GetNextEvent() string {
@ -56,172 +74,252 @@ func (eh *EventHandler) GetNextEvent() string {
select {
case e := <-appChan:
return eh.handleAppBusEvent(&e)
case ev := <-eh.profileEvents:
return eh.handleProfileEvent(&ev)
default:
select {
case e := <-appChan:
return eh.handleAppBusEvent(&e)
case ev := <-eh.profileEvents:
return eh.handleProfileEvent(&ev)
}
}
}
// track acnStatus across events
var acnStatus = -1
// handleAppBusEvent enriches AppBus events so they are usable with out further data fetches
func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
log.Debugf("New AppBus Event to Handle: %v", e)
if eh.app != nil {
switch e.EventType {
case event.ACNStatus:
if e.Data[event.Progress] == "100" {
for onion := range eh.app.ListPeers() {
// launch a listen thread (internally this does a check that the protocol engine is not listening)
// and as such is safe to call.
eh.app.GetPeer(onion).Listen()
newAcnStatus, err := strconv.Atoi(e.Data[event.Progress])
if err != nil {
break
}
if newAcnStatus == 100 {
if acnStatus != 100 {
// just came online
doServers := false
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
doServers = true
}
for _, onion := range eh.app.ListProfiles() {
profile := eh.app.GetPeer(onion)
autostart, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerAutostart)
if !exists || autostart == "true" {
eh.app.ActivatePeerEngine(onion, true, true, doServers)
}
}
eh.api.LaunchServers()
}
} else {
if acnStatus == 100 {
// just fell offline
for _, onion := range eh.app.ListProfiles() {
eh.app.DeactivatePeerEngine(onion)
}
eh.api.StopServers()
}
}
acnStatus = newAcnStatus
case event.NewPeer:
onion := e.Data[event.Identity]
profile := eh.app.GetPeer(e.Data[event.Identity])
if profile == nil {
log.Errorf("NewPeer: skipping profile initialization. this should only happen when the app is rapidly opened+closed (eg during testing)")
break
}
log.Debug("New Peer Event: %v", e)
if e.Data["Reload"] != event.True {
eh.startHandlingPeer(onion)
}
tag, isTagged := profile.GetAttribute(app.AttributeTag)
if isTagged {
e.Data[app.AttributeTag] = tag
} else {
// Assume encrypted for non-tagged profiles - this isn't always true, but all post-beta profiles
// are tagged on creation.
e.Data[app.AttributeTag] = constants.ProfileTypeV1Password
}
// CwtchPeer will always set this now...
tag, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants.Tag)
e.Data[constants.Tag] = tag
if e.Data[event.Created] == event.True {
name, _ := profile.GetAttribute(attr.GetLocalScope(constants.Name))
profile.SetAttribute(attr.GetPublicScope(constants.Name), name)
profile.SetAttribute(attr.GetPublicScope(constants.Picture), ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
profile.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants2.Picture, ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro)))
}
if e.Data[event.Status] != event.StorageRunning || e.Data[event.Created] == event.True {
profile.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
// If the user has chosen to block unknown profiles
// then explicitly configure the protocol engine to do so..
if ReadGlobalSettings().BlockUnknownConnections {
profile.BlockUnknownConnections()
} else {
// For completeness
profile.AllowUnknownConnections()
}
profile.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline, event.False)
// disabeling network check for connection attempt reservation, needs rework
//eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK)
eh.app.AddPeerPlugin(onion, plugins.ANTISPAM)
// Start up the Profile
profile.Listen()
profile.StartPeersConnections()
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
profile.StartServerConnections()
// If the user has chosen to block unknown profiles
// then explicitly configure the protocol engine to do so..
settings := ReadGlobalSettings()
if settings.BlockUnknownConnections {
profile.BlockUnknownConnections()
} else {
// For completeness
profile.AllowUnknownConnections()
}
// Start up the Profile
if acnStatus == 100 {
autostart, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerAutostart)
if !exists || autostart == "true" {
doServers := false
if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil {
doServers = true
}
eh.app.ActivatePeerEngine(onion, true, true, doServers)
}
}
nick, exists := profile.GetAttribute(attr.GetPublicScope(constants.Name))
if !exists {
nick = onion
}
picVal, ok := profile.GetAttribute(attr.GetPublicScope(constants.Picture))
if !ok {
picVal = ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))
}
pic, err := StringToImage(picVal)
if err != nil {
pic = NewImage(RandomProfileImage(onion), TypeImageDistro)
}
picPath := GetPicturePath(pic)
//tag, _ := profile.GetAttribute(app.AttributeTag)
online, _ := profile.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
e.Data[constants.Name] = nick
e.Data[constants.Picture] = picPath
online, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline)
e.Data["Online"] = online
autostart, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerAutostart)
// legacy profiles should autostart by default
if !exists {
autostart = "true"
}
e.Data["autostart"] = autostart
// Name always exists
e.Data[constants.Name], _ = profile.GetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
e.Data[constants2.DefaultProfilePicture] = RandomProfileImage(onion)
// if a custom profile image exists then default to it.
key, exists := profile.GetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.CustomProfileImageKey)
if !exists {
e.Data[constants2.Picture] = RandomProfileImage(onion)
} else {
e.Data[constants2.Picture], _ = profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", key))
}
// Construct our conversations and our srever lists
var contacts []Contact
var servers []groups.Server
for _, contact := range profile.GetContacts() {
// Only compile the server info if we have enabled the experiment...
// Note that this means that this info can become stale if when first loaded the experiment
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
if profile.GetContact(contact).IsServer() {
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
if err == nil {
servers = append(servers, groupHandler.GetServerInfo(contact, profile))
conversations, err := profile.FetchConversations()
if err == nil {
// We have conversations attached to this profile...
for _, conversationInfo := range conversations {
// Only compile the server info if we have enabled the experiment...
// Note that this means that this info can become stale if when first loaded the experiment
// has been disabled and then is later re-enabled. As such we need to ensure that this list is
// re-fetched when the group experiment is enabled via a dedicated ListServerInfo event...
if conversationInfo.IsServer() {
groupHandler, err := groups.ExperimentGate(ReadGlobalSettings().Experiments)
if err == nil {
servers = append(servers, groupHandler.GetServerInfo(conversationInfo.Handle, profile))
}
continue
}
continue
}
contactInfo := profile.GetContact(contact)
ph := NewPeerHelper(profile)
name := ph.GetNick(contact)
cpicPath := ph.GetProfilePic(contact)
saveHistory, set := contactInfo.GetAttribute(event.SaveHistoryKey)
if !set {
saveHistory = event.DeleteHistoryDefault
}
isArchived, set := contactInfo.GetAttribute(attr.GetLocalScope(constants.Archived))
if !set {
isArchived = event.False
}
contacts = append(contacts, Contact{
Name: name,
Onion: contactInfo.Onion,
Status: contactInfo.State,
Picture: cpicPath,
Authorization: string(contactInfo.Authorization),
SaveHistory: saveHistory,
Messages: contactInfo.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&contactInfo.Timeline)),
IsGroup: false,
IsArchived: isArchived == event.True,
})
}
// Prefer local override to public name...
name, exists := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.Name)
if !exists {
name, exists = conversationInfo.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
if !exists {
name = conversationInfo.Handle
}
}
// We compile and send the groups regardless of the experiment flag, and hide them in the UI
for _, groupId := range profile.GetGroups() {
group := profile.GetGroup(groupId)
// Resolve the profile image of the contact
var cpicPath string
var defaultPath string
if conversationInfo.IsGroup() {
cpicPath = RandomGroupImage(conversationInfo.Handle)
defaultPath = RandomGroupImage(conversationInfo.Handle)
} else {
cpicPath = GetProfileImage(profile, conversationInfo, settings.DownloadPath)
defaultPath = RandomProfileImage(conversationInfo.Handle)
}
// Check that the group is cryptographically valid
if !group.CheckGroup() {
continue
// Resolve Save History Setting
saveHistory, set := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, event.SaveHistoryKey)
if !set {
saveHistory = event.DeleteHistoryDefault
}
// Resolve Archived Setting
isArchived, set := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, constants2.Archived)
if !set {
isArchived = event.False
}
unread := 0
lastSeenMessageId := -1
lastSeenTimeStr, set := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, constants2.LastSeenTime)
if set {
lastSeenTime, err := time.Parse(constants2.DartIso8601, lastSeenTimeStr)
if err == nil {
// get last 100 messages and count how many are after the lastSeenTime (100 cus hte ui just shows 99+ after)
messages, err := profile.GetMostRecentMessages(conversationInfo.ID, 0, 0, 100)
if err == nil {
for _, message := range messages {
msgTime, err := time.Parse(time.RFC3339Nano, message.Attr[constants.AttrSentTimestamp])
if err == nil {
if msgTime.UTC().After(lastSeenTime.UTC()) {
unread++
} else {
lastSeenMessageId = message.ID
break
}
}
}
}
}
}
groupServer, _ := conversationInfo.GetAttribute(attr.LocalScope, attr.LegacyGroupZone, constants.GroupServer)
stateHandle := conversationInfo.Handle
if conversationInfo.IsGroup() {
stateHandle = groupServer
}
state := profile.GetPeerState(stateHandle)
if !set {
state = connections.DISCONNECTED
}
blocked := false
if conversationInfo.ACL[conversationInfo.Handle].Blocked {
blocked = true
}
// Fetch the message count, and the time of the most recent message
count, err := profile.GetChannelMessageCount(conversationInfo.ID, 0)
if err != nil {
log.Errorf("error fetching channel message count %v %v", conversationInfo.ID, err)
}
lastMessage, _ := profile.GetMostRecentMessages(conversationInfo.ID, 0, 0, 1)
notificationPolicy := constants2.ConversationNotificationPolicyDefault
if notificationPolicyAttr, exists := conversationInfo.GetAttribute(attr.LocalScope, attr.ProfileZone, constants2.ConversationNotificationPolicy); exists {
notificationPolicy = notificationPolicyAttr
}
contacts = append(contacts, Contact{
Name: name,
Identifier: conversationInfo.ID,
Onion: conversationInfo.Handle,
Status: connections.ConnectionStateName[state],
Picture: cpicPath,
DefaultPicture: defaultPath,
Accepted: conversationInfo.Accepted,
AccessControlList: conversationInfo.ACL,
Blocked: blocked,
SaveHistory: saveHistory,
Messages: count,
Unread: unread,
LastSeenMessageId: lastSeenMessageId,
LastMessage: strconv.Itoa(getLastMessageTime(lastMessage)),
IsGroup: conversationInfo.IsGroup(),
GroupServer: groupServer,
IsArchived: isArchived == event.True,
NotificationPolicy: notificationPolicy,
Attributes: conversationInfo.Attributes,
})
}
ph := NewPeerHelper(profile)
cpicPath := ph.GetProfilePic(groupId)
authorization := model.AuthUnknown
if group.Accepted {
authorization = model.AuthApproved
}
isArchived, set := group.GetAttribute(attr.GetLocalScope(constants.Archived))
if !set {
isArchived = event.False
}
// Use the server state when assessing group state
state := profile.GetContact(group.GroupServer).State
contacts = append(contacts, Contact{
Name: ph.GetNick(groupId),
Onion: group.GroupID,
Status: state,
Picture: cpicPath,
Authorization: string(authorization),
SaveHistory: event.SaveHistoryConfirmed,
Messages: group.Timeline.Len(),
Unread: 0,
LastMessage: strconv.Itoa(getLastMessageTime(&group.Timeline)),
IsGroup: true,
GroupServer: group.GroupServer,
IsArchived: isArchived == event.True,
})
}
bytes, _ := json.Marshal(contacts)
@ -239,99 +337,302 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string {
return string(json)
}
func GetProfileImage(profile peer.CwtchPeer, conversationInfo *model.Conversation, basepath string) string {
fileKey, err := profile.GetConversationAttribute(conversationInfo.ID, attr.PublicScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.CustomProfileImageKey)))
if err == nil {
if value, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.complete", fileKey)); exists && value == event.True {
fp, _ := filesharing.GenerateDownloadPath(basepath, fileKey, true)
// check if the file exists...if it does then set the path...
if _, err := os.Stat(fp); err == nil {
image, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", fileKey))
return image
}
}
}
return RandomProfileImage(conversationInfo.Handle)
}
// handleProfileEvent enriches Profile events so they are usable with out further data fetches
func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string {
// cache of contact states to use to filter out events repeating known states
var contactStateCache = make(map[string]connections.ConnectionState)
if eh.app == nil {
log.Errorf("eh.app == nil in handleProfileEvent... this shouldnt happen?")
} else {
peer := eh.app.GetPeer(ev.Profile)
ph := NewPeerHelper(peer)
profile := eh.app.GetPeer(ev.Profile)
log.Debugf("New Profile Event to Handle: %v", ev)
switch ev.Event.EventType {
/*
TODO: still handle this somewhere - network info from plugin Network check
case event.NetworkStatus:
online, _ := peer.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
if e.Data[event.Status] == plugins.NetworkCheckSuccess && online == event.False {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.True)
uiManager.UpdateNetworkStatus(true)
// TODO we may have to reinitialize the peer
} else if e.Data[event.Status] == plugins.NetworkCheckError && online == event.True {
peer.SetAttribute(attr.GetLocalScope(constants.PeerOnline), event.False)
uiManager.UpdateNetworkStatus(false)
}*/
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
// only needs contact nickname and picture, for displaying on popup notifications
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data["RemotePeer"])
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data["RemotePeer"])
peer.SetContactAttribute(ev.Event.Data["RemotePeer"], attr.GetLocalScope(constants.Archived), event.False)
case event.NewMessageFromGroup:
// only needs contact nickname and picture, for displaying on popup notifications
ev.Event.Data["Nick"] = ph.GetNick(ev.Event.Data[event.GroupID])
ev.Event.Data["Picture"] = ph.GetProfilePic(ev.Event.Data[event.GroupID])
peer.SetGroupAttribute(ev.Event.Data[event.GroupID], attr.GetLocalScope(constants.Archived), event.False)
case event.PeerAcknowledgement:
// No enrichement required
case event.PeerCreated:
handle := ev.Event.Data[event.RemotePeer]
err := EnrichNewPeer(handle, ph, ev)
if err != nil {
ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"])
ev.Event.Data[constants2.Picture] = RandomProfileImage(ev.Event.Data["RemotePeer"])
if ci != nil && err == nil {
ev.Event.Data[event.ConversationID] = strconv.Itoa(ci.ID)
profile.SetConversationAttribute(ci.ID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants2.Archived)), event.False)
ev.Event.Data[constants2.Picture] = GetProfileImage(profile, ci, ReadGlobalSettings().DownloadPath)
} else {
// TODO This Conversation May Not Exist Yet...But we are not in charge of creating it...
log.Errorf("todo wait for contact to be added before processing this event...")
return ""
}
var exists bool
ev.Event.Data["Nick"], exists = ci.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.Name)
if !exists {
ev.Event.Data["Nick"], exists = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
if !exists {
ev.Event.Data["Nick"] = ev.Event.Data["RemotePeer"]
// If we dont have a name val for a peer, but they have sent us a message, we might be approved now, re-ask
profile.SendScopedZonedGetValToContact(ci.ID, attr.PublicScope, attr.ProfileZone, constants.Name)
profile.SendScopedZonedGetValToContact(ci.ID, attr.PublicScope, attr.ProfileZone, constants.CustomProfileImageKey)
}
}
if ci.Accepted {
handleImagePreviews(profile, &ev.Event, ci.ID, ci.ID)
}
ev.Event.Data["notification"] = string(determineNotification(ci))
case event.NewMessageFromGroup:
// only needs contact nickname and picture, for displaying on popup notifications
ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"])
ev.Event.Data[constants2.Picture] = RandomProfileImage(ev.Event.Data["RemotePeer"])
if ci != nil && err == nil {
var exists bool
ev.Event.Data["Nick"], exists = ci.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.Name)
if !exists {
ev.Event.Data["Nick"], exists = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name)
if !exists {
ev.Event.Data["Nick"] = ev.Event.Data["RemotePeer"]
}
}
ev.Event.Data[constants2.Picture] = GetProfileImage(profile, ci, ReadGlobalSettings().DownloadPath)
}
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
profile.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants2.Archived)), event.False)
if ci != nil && ci.Accepted {
handleImagePreviews(profile, &ev.Event, conversationID, ci.ID)
}
gci, _ := profile.GetConversationInfo(conversationID)
groupServer := gci.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupServer)).ToString()]
state := profile.GetPeerState(groupServer)
// if syncing, don't flood with notifications
if state == connections.SYNCED {
ev.Event.Data["notification"] = string(determineNotification(gci))
} else {
ev.Event.Data["notification"] = string(constants2.NotificationNone)
}
case event.PeerAcknowledgement:
ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"])
if ci != nil && err == nil {
ev.Event.Data[event.ConversationID] = strconv.Itoa(ci.ID)
}
case event.ContactCreated:
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
count, err := profile.GetChannelMessageCount(conversationID, 0)
if err != nil {
log.Errorf("error fetching channel message count %v %v", conversationID, err)
}
conversationInfo, err := profile.GetConversationInfo(conversationID)
if err != nil {
log.Errorf("error fetching conversation info for %v %v", conversationID, err)
}
blocked := constants.False
if conversationInfo.ACL[conversationInfo.Handle].Blocked {
blocked = constants.True
}
accepted := constants.False
if conversationInfo.Accepted {
accepted = constants.True
}
acl, _ := json.Marshal(conversationInfo.ACL)
lastMessage, _ := profile.GetMostRecentMessages(conversationID, 0, 0, 1)
ev.Event.Data["unread"] = strconv.Itoa(count) // if this is a new contact with messages attached then by-definition these are unread...
ev.Event.Data[constants2.Picture] = RandomProfileImage(conversationInfo.Handle)
ev.Event.Data[constants2.DefaultProfilePicture] = RandomProfileImage(conversationInfo.Handle)
ev.Event.Data["numMessages"] = strconv.Itoa(count)
ev.Event.Data["nick"] = conversationInfo.Handle
ev.Event.Data["status"] = connections.ConnectionStateName[profile.GetPeerState(conversationInfo.Handle)]
ev.Event.Data["accepted"] = accepted
ev.Event.Data["accessControlList"] = string(acl)
ev.Event.Data["blocked"] = blocked
ev.Event.Data["loading"] = "false"
ev.Event.Data["lastMsgTime"] = strconv.Itoa(getLastMessageTime(lastMessage))
case event.GroupCreated:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
groupPic := RandomGroupImage(ev.Event.Data[event.GroupID])
ev.Event.Data[constants2.Picture] = groupPic
groupPic := ph.GetProfilePic(ev.Event.Data[event.GroupID])
ev.Event.Data["PicturePath"] = groupPic
ev.Event.Data["GroupName"] = ph.GetNick(ev.Event.Data[event.GroupID])
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
conversationInfo, _ := profile.GetConversationInfo(conversationID)
acl, _ := json.Marshal(conversationInfo.ACL)
ev.Event.Data["accessControlList"] = string(acl)
case event.NewGroup:
// This event should only happen after we have validated the invite, as such the error
// condition *should* never happen.
serializedInvite := ev.Event.Data[event.GroupInvite]
if invite, err := model.ValidateInvite(serializedInvite); err == nil {
groupPic := ph.GetProfilePic(invite.GroupID)
ev.Event.Data["PicturePath"] = groupPic
groupPic := RandomGroupImage(invite.GroupID)
ev.Event.Data[constants2.Picture] = groupPic
conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID])
conversationInfo, _ := profile.GetConversationInfo(conversationID)
acl, _ := json.Marshal(conversationInfo.ACL)
ev.Event.Data["accessControlList"] = string(acl)
} else {
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivcy.ca/cwtch.im/cwtch", err)
log.Errorf("received a new group event which contained an invalid invite %v. this should never happen and likely means there is a bug in cwtch. Please file a ticket @ https://git.openprivacy.ca/cwtch.im/cwtch", err)
return ""
}
case event.PeerStateChange:
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
contact := peer.GetContact(ev.Event.Data[event.RemotePeer])
if cxnState == connections.AUTHENTICATED && contact == nil {
peer.AddContact(ev.Event.Data[event.RemotePeer], ev.Event.Data[event.RemotePeer], model.AuthUnknown)
// skip events the UI doesn't act on
if cxnState == connections.CONNECTING || cxnState == connections.CONNECTED {
return ""
}
contact, err := profile.FetchConversationInfo(ev.Event.Data[event.RemotePeer])
if ev.Event.Data[event.RemotePeer] == profile.GetOnion() {
return "" // suppress events from our own profile...
}
// We do not know who this is...don't send any event until we see a message from them
// (at that point the conversation will have been created...)
if contact == nil || err != nil || contact.ID == 0 {
return ""
}
// if we already know this state, suppress
if knownState, exists := contactStateCache[ev.Event.Data[event.RemotePeer]]; exists && cxnState == knownState {
return ""
}
contactStateCache[ev.Event.Data[event.RemotePeer]] = cxnState
if contact != nil {
// No enrichment needed
//uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
if cxnState == connections.AUTHENTICATED {
// if known and authed, get vars
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Name)
peer.SendGetValToPeer(ev.Event.Data[event.RemotePeer], attr.PublicScope, constants.Picture)
profile.SendScopedZonedGetValToContact(contact.ID, attr.PublicScope, attr.ProfileZone, constants.Name)
profile.SendScopedZonedGetValToContact(contact.ID, attr.PublicScope, attr.ProfileZone, constants.CustomProfileImageKey)
}
}
case event.ServerStateChange:
cxnState := connections.ConnectionStateToType()[ev.Event.Data[event.ConnectionState]]
// skip events the UI doesn't act on
if cxnState == connections.CONNECTING || cxnState == connections.CONNECTED {
return ""
}
// if we already know this state, suppress
if knownState, exists := contactStateCache[ev.Event.Data[event.RemotePeer]]; exists && cxnState == knownState {
return ""
}
contactStateCache[ev.Event.Data[event.RemotePeer]] = cxnState
case event.NewRetValMessageFromPeer:
// auto handled event means the setting is already done, we're just deciding if we need to tell the UI
onion := ev.Event.Data[event.RemotePeer]
scope := ev.Event.Data[event.Scope]
path := ev.Event.Data[event.Path]
//val := ev.Event.Data[event.Data]
val := ev.Event.Data[event.Data]
exists, _ := strconv.ParseBool(ev.Event.Data[event.Exists])
if exists && scope == attr.PublicScope {
if _, exists := peer.GetContactAttribute(onion, attr.GetLocalScope(path)); exists {
// we have a locally set ovverride, don't pass this remote set public scope update to UI
return ""
conversation, err := profile.FetchConversationInfo(onion)
if err == nil {
if exists && attr.IntoScope(scope) == attr.PublicScope {
zone, path := attr.ParseZone(path)
// auto download profile images from contacts...
settings := ReadGlobalSettings()
if settings.ExperimentsEnabled && zone == attr.ProfileZone && path == constants.CustomProfileImageKey {
fileKey := val
fsf, err := filesharing.FunctionalityGate(settings.Experiments)
imagePreviewsEnabled := settings.Experiments["filesharing-images"]
if err == nil && imagePreviewsEnabled && conversation.Accepted {
basepath := settings.DownloadPath
fp, mp := filesharing.GenerateDownloadPath(basepath, fileKey, true)
if value, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.complete", fileKey)); exists && value == event.True {
if _, err := os.Stat(fp); err == nil {
// file is marked as completed downloaded and exists...
return ""
} else {
// the user probably deleted the file, mark completed as false...
profile.SetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.complete", fileKey), event.False)
}
}
log.Debugf("Downloading Profile Image %v %v %v", fp, mp, fileKey)
ev.Event.Data[event.FilePath] = fp
fsf.DownloadFile(profile, conversation.ID, fp, mp, val, constants.ImagePreviewMaxSizeInBytes)
} else {
// if image previews are disabled then ignore this event...
return ""
}
}
if val, err := profile.GetConversationAttribute(conversation.ID, attr.LocalScope.ConstructScopedZonedPath(zone.ConstructZonedPath(path))); err == nil || val != "" {
// we have a locally set override, don't pass this remote set public scope update to UI
return ""
}
}
}
case event.TokenManagerInfo:
conversations, err := profile.FetchConversations()
if err == nil {
var associatedGroups []int
for _, ci := range conversations {
groupServer, groupServerExists := ci.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupServer)).ToString()]
if groupServerExists {
gci, err := profile.FetchConversationInfo(groupServer)
if err == nil {
tokenOnion, onionExists := gci.Attributes[attr.PublicScope.ConstructScopedZonedPath(attr.ServerKeyZone.ConstructZonedPath(string(model.KeyTypeTokenOnion))).ToString()]
if onionExists && tokenOnion == ev.Event.Data[event.ServerTokenOnion] {
associatedGroups = append(associatedGroups, ci.ID)
}
}
}
}
associatedGroupsJson, _ := json.Marshal(associatedGroups)
ev.Event.Data[event.Data] = string(associatedGroupsJson)
}
case event.ProtocolEngineCreated:
// TODO this code should be moved into Cwtch during the API officialization...
settings := ReadGlobalSettings()
// ensure that protocol engine respects blocking settings...
if settings.BlockUnknownConnections {
profile.BlockUnknownConnections()
} else {
profile.AllowUnknownConnections()
}
// Now that the Peer Engine is Activated, Share Files
key, exists := profile.GetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.CustomProfileImageKey)
if exists {
serializedManifest, _ := profile.GetScopedZonedAttribute(attr.ConversationScope, attr.FilesharingZone, fmt.Sprintf("%s.manifest", key))
// reset the share timestamp, currently file shares are hardcoded to expire after 30 days...
// we reset the profile image here so that it is always available.
profile.SetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.ts", key), strconv.FormatInt(time.Now().Unix(), 10))
log.Debugf("Custom Profile Image: %v %s", key, serializedManifest)
}
// If file sharing is enabled then reshare all active files...
fsf, err := filesharing.FunctionalityGate(settings.Experiments)
if err == nil {
fsf.ReShareFiles(profile)
}
}
}
@ -348,30 +649,23 @@ func unwrap(original *EventProfileEnvelope) *event.Event {
func (eh *EventHandler) startHandlingPeer(onion string) {
eventBus := eh.app.GetEventBus(onion)
q := event.NewQueue()
eventBus.Subscribe(event.NetworkStatus, q)
eventBus.Subscribe(event.ACNInfo, q)
eventBus.Subscribe(event.NewMessageFromPeer, q)
eventBus.Subscribe(event.UpdatedProfileAttribute, q)
eventBus.Subscribe(event.PeerAcknowledgement, q)
eventBus.Subscribe(event.DeleteContact, q)
eventBus.Subscribe(event.AppError, q)
eventBus.Subscribe(event.IndexedAcknowledgement, q)
eventBus.Subscribe(event.IndexedFailure, q)
eventBus.Subscribe(event.ContactCreated, q)
eventBus.Subscribe(event.NewMessageFromGroup, q)
eventBus.Subscribe(event.MessageCounterResync, q)
eventBus.Subscribe(event.GroupCreated, q)
eventBus.Subscribe(event.NewGroup, q)
eventBus.Subscribe(event.AcceptGroupInvite, q)
eventBus.Subscribe(event.SetPeerAttribute, q)
eventBus.Subscribe(event.SetGroupAttribute, q)
eventBus.Subscribe(event.DeleteGroup, q)
eventBus.Subscribe(event.SendMessageToGroupError, q)
eventBus.Subscribe(event.SendMessageToPeerError, q)
eventBus.Subscribe(event.ServerStateChange, q)
eventBus.Subscribe(event.PeerStateChange, q)
eventBus.Subscribe(event.PeerCreated, q)
eventBus.Subscribe(event.NetworkStatus, q)
eventBus.Subscribe(event.ChangePasswordSuccess, q)
eventBus.Subscribe(event.ChangePasswordError, q)
eventBus.Subscribe(event.NewRetValMessageFromPeer, q)
eventBus.Subscribe(event.SetAttribute, q)
eventBus.Subscribe(event.ShareManifest, q)
eventBus.Subscribe(event.ManifestSizeReceived, q)
eventBus.Subscribe(event.ManifestError, q)
@ -379,7 +673,8 @@ func (eh *EventHandler) startHandlingPeer(onion string) {
eventBus.Subscribe(event.ManifestSaved, q)
eventBus.Subscribe(event.FileDownloadProgressUpdate, q)
eventBus.Subscribe(event.FileDownloaded, q)
eventBus.Subscribe(event.TokenManagerInfo, q)
eventBus.Subscribe(event.ProtocolEngineCreated, q)
go eh.forwardProfileMessages(onion, q)
}
@ -397,6 +692,65 @@ func (eh *EventHandler) forwardProfileMessages(onion string, q event.Queue) {
}
}
// Push pushes an event onto the app event bus
//
// It is also a way for libCwtch-go to publish an event for consumption by a UI before a Cwtch app has been initialized
// use: to signal an error before a cwtch app could be created
func (eh *EventHandler) Push(newEvent event.Event) {
eh.appBusQueue.Publish(newEvent)
}
func getLastMessageTime(conversationMessages []model.ConversationMessage) int {
if len(conversationMessages) == 0 {
return 0
}
time, err := time.Parse(time.RFC3339Nano, conversationMessages[0].Attr[constants.AttrSentTimestamp])
if err != nil {
return 0
}
return int(time.Unix())
}
// handleImagePreviews checks settings and, if appropriate, auto-downloads any images
func handleImagePreviews(profile peer.CwtchPeer, ev *event.Event, conversationID, senderID int) {
settings := ReadGlobalSettings()
fh, err := filesharing.PreviewFunctionalityGate(settings.Experiments)
// Short-circuit if file sharing is disabled
if err != nil {
return
}
// Short-circuit failures
// Don't autodownload images if the download path does not exist.
if settings.DownloadPath == "" {
return
}
// Don't autodownload images if the download path does not exist.
if _, err := os.Stat(settings.DownloadPath); os.IsNotExist(err) {
return
}
// Now look at the image preview experiment
imagePreviewsEnabled := settings.Experiments["filesharing-images"]
if imagePreviewsEnabled {
var cm model.MessageWrapper
err := json.Unmarshal([]byte(ev.Data[event.Data]), &cm)
if err == nil && cm.Overlay == model.OverlayFileSharing {
var fm filesharing.OverlayMessage
err = json.Unmarshal([]byte(cm.Data), &fm)
if err == nil {
if fm.ShouldAutoDL() {
basepath := settings.DownloadPath
fp, mp := filesharing.GenerateDownloadPath(basepath, fm.Name, false)
log.Debugf("autodownloading file!")
ev.Data["Auto"] = constants.True
mID, _ := strconv.Atoi(ev.Data["Index"])
profile.UpdateMessageAttribute(conversationID, 0, mID, constants.AttrDownloaded, constants.True)
fh.DownloadFile(profile, senderID, fp, mp, fm.FileKey(), constants.ImagePreviewMaxSizeInBytes)
}
}
}
}
}

View File

@ -1,395 +0,0 @@
package utils
import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/protocol/connections"
"errors"
"git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
"git.openprivacy.ca/openprivacy/log"
"strconv"
"strings"
"time"
)
type PeerHelper struct {
peer peer.CwtchPeer
}
func NewPeerHelper(profile peer.CwtchPeer) *PeerHelper {
return &PeerHelper{profile}
}
func (p *PeerHelper) IsGroup(id string) bool {
return len(id) == 32 && !p.IsServer(id)
}
func (p *PeerHelper) IsPeer(id string) bool {
return len(id) == 56 && !p.IsServer(id)
}
// Check if the id is associated with a contact with a KeyTypeServerOnion attribute (which indicates that this
// is a server, not a regular contact or a group
func (p *PeerHelper) IsServer(id string) bool {
_, ok := p.peer.GetContactAttribute(id, string(model.KeyTypeServerOnion))
return ok
}
// GetTimeline returns a pointer to the timeline associated with the conversation handle or nil if the handle
// does not exist (this can happen if the conversation has been deleted)
func (p *PeerHelper) GetTimeline(handle string) *model.Timeline {
if p.IsServer(handle) {
// This should *never* happen
log.Errorf("server accessed as contact when getting timeline...")
return &model.Timeline{}
}
// We return a pointer to the timeline to avoid copying, accessing Timeline is thread-safe
if p.IsGroup(handle) {
group := p.peer.GetGroup(handle)
if group == nil {
return nil
}
return &group.Timeline
}
contact := p.peer.GetContact(handle)
if contact == nil {
return nil
}
return &contact.Timeline
}
/*
func getOrDefault(id, key string, defaultVal string) string {
var val string
var ok bool
if IsGroup(id) {
val, ok = the.Peer.GetGroupAttribute(id, key)
} else {
val, ok = the.Peer.GetContactAttribute(id, key)
}
if ok {
return val
} else {
return defaultVal
}
}*/
func (p *PeerHelper) GetWithSetDefault(id string, key string, defaultVal string) string {
var val string
var ok bool
if p.IsGroup(id) {
val, ok = p.peer.GetGroupAttribute(id, key)
} else {
val, ok = p.peer.GetContactAttribute(id, key)
}
if !ok {
val = defaultVal
if p.IsGroup(id) {
p.peer.SetGroupAttribute(id, key, defaultVal)
} else {
p.peer.SetContactAttribute(id, key, defaultVal)
}
}
return val
}
func (p *PeerHelper) GetNick(id string) string {
if p.IsGroup(id) {
nick, exists := p.peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Name))
if !exists || nick == "" || nick == id {
nick, exists = p.peer.GetGroupAttribute(id, attr.GetPeerScope(constants.Name))
if !exists {
nick = "[" + id + "]"
}
}
return nick
} else {
nick, exists := p.peer.GetContactAttribute(id, attr.GetLocalScope(constants.Name))
if !exists || nick == "" || nick == id {
nick, exists = p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Name))
if !exists {
nick = "[" + id + "]"
// we do not have a canonical nick for this contact.
// re-request if authenticated
// TODO: This check probably doesn't belong here...
if contact := p.peer.GetContact(id); contact != nil && contact.State == connections.ConnectionStateName[connections.AUTHENTICATED] {
p.peer.SendGetValToPeer(id, attr.PublicScope, constants.Name)
}
}
}
return nick
}
}
// InitLastReadTime checks and gets the Attributable's LastRead time or sets it to now
func (p *PeerHelper) InitLastReadTime(id string) time.Time {
nowStr, _ := time.Now().MarshalText()
lastReadAttr := p.GetWithSetDefault(id, attr.GetLocalScope(constants.LastRead), string(nowStr))
var lastRead time.Time
lastRead.UnmarshalText([]byte(lastReadAttr))
return lastRead
}
// GetProfilePic returns a string path to an image to display for hte given peer/group id
func (p *PeerHelper) GetProfilePic(id string) string {
if p.IsGroup(id) {
if picVal, exists := p.peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Picture)); exists {
pic, err := StringToImage(picVal)
if err == nil {
return GetPicturePath(pic)
}
}
if picVal, exists := p.peer.GetGroupAttribute(id, attr.GetPeerScope(constants.Picture)); exists {
pic, err := StringToImage(picVal)
if err == nil {
return GetPicturePath(pic)
}
}
return GetPicturePath(NewImage(RandomGroupImage(id), TypeImageDistro))
} else {
if picVal, exists := p.peer.GetContactAttribute(id, attr.GetLocalScope(constants.Picture)); exists {
pic, err := StringToImage(picVal)
if err == nil {
return GetPicturePath(pic)
}
}
if picVal, exists := p.peer.GetContactAttribute(id, attr.GetPeerScope(constants.Picture)); exists {
pic, err := StringToImage(picVal)
if err == nil {
return GetPicturePath(pic)
}
}
return RandomProfileImage(id)
}
}
// a lot of pics were stored full path + uri. remove all this to the relative path in images/
// fix for storing full paths introduced 2019.12
func profilePicRelativize(filename string) string {
parts := strings.Split(filename, "qml/images")
return parts[len(parts)-1]
}
func GetPicturePath(pic *image) string {
switch pic.T {
case TypeImageDistro:
return profilePicRelativize(pic.Val)
default:
log.Errorf("Unhandled profile picture type of %v\n", pic.T)
return ""
}
}
func (p *PeerHelper) CountUnread(messages []model.Message, lastRead time.Time) int {
count := 0
for i := len(messages) - 1; i >= 0; i-- {
if messages[i].Timestamp.After(lastRead) || messages[i].Timestamp.Equal(lastRead) {
count++
} else {
break
}
}
return count
}
func getLastMessageTime(tl *model.Timeline) int {
if len(tl.Messages) == 0 {
return 0
}
return int(tl.Messages[len(tl.Messages)-1].Timestamp.Unix())
}
/*
// AddProfile adds a new profile to the UI
func AddProfile(gcd *GrandCentralDispatcher, handle string) {
p := the.CwtchApp.GetPeer(handle)
if p != nil {
nick, exists := p.GetAttribute(attr.GetPublicScope(constants.Name))
if !exists {
nick = handle
}
picVal, ok := p.GetAttribute(attr.GetPublicScope(constants.Picture))
if !ok {
picVal = ImageToString(NewImage(RandomProfileImage(handle), TypeImageDistro))
}
pic, err := StringToImage(picVal)
if err != nil {
pic = NewImage(RandomProfileImage(handle), TypeImageDistro)
}
picPath := getPicturePath(pic)
tag, _ := p.GetAttribute(app.AttributeTag)
online, _ := p.GetAttribute(attr.GetLocalScope(constants.PeerOnline))
log.Debugf("AddProfile %v %v %v %v %v\n", handle, nick, picPath, tag, online)
gcd.AddProfile(handle, nick, picPath, tag, online == event.True)
}
}*/
/*
type manager struct {
gcd *GrandCentralDispatcher
profile string
}
// Manager is a middleware helper for entities like peer event listeners wishing to trigger ui changes (via the gcd)
// each manager is for one profile/peer
// manager takes minimal arguments and builds the full struct of data (usually pulled from a cwtch peer) required to call the GCD to perform the ui action
// manager also performs call filtering based on UI state: users of manager can safely always call it on events and not have to worry about weather the relevant ui is active
// ie: you can always safely call AddMessage even if in the ui a different profile is selected. manager will check with gcd, and if the correct conditions are not met, it will not call on gcd to update the ui incorrectly
type Manager interface {
Acknowledge(handle, mID string)
AddContact(Handle string)
AddSendMessageError(peer string, signature string, err string)
AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool)
ReloadProfiles()
UpdateContactDisplayName(handle string)
UpdateContactPicture(handle string)
UpdateContactStatus(handle string, status int, loading bool)
UpdateContactAttribute(handle, key, value string)
ChangePasswordResponse(error bool)
AboutToAddMessage()
MessageJustAdded()
StoreAndNotify(peer.CwtchPeer, string, string, time.Time, string)
UpdateNetworkStatus(online bool)
}
// NewManager returns a new Manager interface for a profile to the gcd
func NewManager(profile string, gcd *GrandCentralDispatcher) Manager {
return &manager{gcd: gcd, profile: profile}
}
*/
// EnrichNewPeer populates required data for use by frontend
// uiManager.AddContact(onion)
// (handle string, displayName string, image string, badge int, status int, authorization string, loading bool, lastMsgTime int)
func EnrichNewPeer(handle string, ph *PeerHelper, ev *EventProfileEnvelope) error {
if ph.IsGroup(handle) {
group := ph.peer.GetGroup(handle)
if group != nil {
lastRead := ph.InitLastReadTime(group.GroupID)
ev.Event.Data["unread"] = strconv.Itoa(ph.CountUnread(group.Timeline.GetMessages(), lastRead))
ev.Event.Data["picture"] = ph.GetProfilePic(handle)
ev.Event.Data["numMessages"] = strconv.Itoa(group.Timeline.Len())
ev.Event.Data["nick"] = ph.GetNick(handle)
ev.Event.Data["status"] = group.State
ev.Event.Data["authorization"] = string(model.AuthApproved)
ev.Event.Data["loading"] = "false"
ev.Event.Data["lastMsgTime"] = strconv.Itoa(getLastMessageTime(&group.Timeline))
}
} else if ph.IsPeer(handle) {
contact := ph.peer.GetContact(handle)
if contact != nil {
lastRead := ph.InitLastReadTime(contact.Onion)
ev.Event.Data["unread"] = strconv.Itoa(ph.CountUnread(contact.Timeline.GetMessages(), lastRead))
ev.Event.Data["numMessages"] = strconv.Itoa(contact.Timeline.Len())
ev.Event.Data["picture"] = ph.GetProfilePic(handle)
ev.Event.Data["nick"] = ph.GetNick(handle)
// TODO Replace this if with a better flow that separates New Contacts and Peering Updates
if contact.State == "" {
// Will be disconnected to start
ev.Event.Data["status"] = connections.ConnectionStateName[connections.DISCONNECTED]
} else {
ev.Event.Data["status"] = contact.State
}
ev.Event.Data["authorization"] = string(contact.Authorization)
ev.Event.Data["loading"] = "false"
ev.Event.Data["lastMsgTime"] = strconv.Itoa(getLastMessageTime(&contact.Timeline))
} else {
log.Errorf("Failed to find contact: %v", handle)
}
} else {
// could be a server?
log.Debugf("sorry, unable to handle AddContact(%v)", handle)
return errors.New("not a peer or group")
}
return nil
}
/*
// AddSendMessageError adds an error not and icon to a message in a conversation in the ui for the message identified by the peer/sig combo
func (this *manager) AddSendMessageError(peer string, signature string, err string) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.DoIfConversation(peer, func() {
log.Debugf("Received Error Sending Message: %v", err)
// FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI
time.Sleep(time.Second * 1)
this.gcd.GroupSendError(signature, err)
})
})
}
func (this *manager) AboutToAddMessage() {
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
}
func (this *manager) MessageJustAdded() {
this.gcd.TimelineInterface.RequestEIR()
}*/
/*
// AddMessage adds a message to the message pane for the supplied conversation if it is active
func (this *manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.DoIfConversation(handle, func() {
updateLastReadTime(handle)
// If the message is not from the user then add it, otherwise, just acknowledge.
if !fromMe || !Acknowledged {
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num() - 1)
this.gcd.TimelineInterface.RequestEIR()
} else {
this.gcd.Acknowledged(messageID)
}
})
this.gcd.IncContactUnreadCount(handle)
})
if !fromMe {
this.gcd.Notify(handle)
}
}
func (this *manager) ReloadProfiles() {
this.gcd.reloadProfileList()
}
// UpdateContactDisplayName updates a contact's display name in the contact list and conversations
func (this *manager) UpdateContactDisplayName(handle string) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.UpdateContactDisplayName(handle, GetNick(handle))
})
}
// UpdateContactPicture updates a contact's picture in the contact list and conversations
func (this *manager) UpdateContactPicture(handle string) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.UpdateContactPicture(handle, GetProfilePic(handle))
})
}
// UpdateContactAttribute update's a contacts attribute in the ui
func (this *manager) UpdateContactAttribute(handle, key, value string) {
this.gcd.DoIfProfile(this.profile, func() {
this.gcd.UpdateContactAttribute(handle, key, value)
})
}
func (this *manager) ChangePasswordResponse(error bool) {
this.gcd.ChangePasswordResponse(error)
}
func (this *manager) UpdateNetworkStatus(online bool) {
this.gcd.UpdateProfileNetworkStatus(this.profile, online)
}
*/

51
utils/notifications.go Normal file
View File

@ -0,0 +1,51 @@
package utils
import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
)
func determineNotification(ci *model.Conversation) constants.NotificationType {
settings := ReadGlobalSettings()
switch settings.NotificationPolicy {
case NotificationPolicyMute:
return constants.NotificationNone
case NotificationPolicyOptIn:
if ci != nil {
if policy, exists := ci.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.ConversationNotificationPolicy); exists {
switch policy {
case constants.ConversationNotificationPolicyDefault:
return constants.NotificationNone
case constants.ConversationNotificationPolicyNever:
return constants.NotificationNone
case constants.ConversationNotificationPolicyOptIn:
return notificationContentToNotificationType(settings.NotificationContent)
}
}
}
return constants.NotificationNone
case NotificationPolicyDefaultAll:
if ci != nil {
if policy, exists := ci.GetAttribute(attr.LocalScope, attr.ProfileZone, constants.ConversationNotificationPolicy); exists {
switch policy {
case constants.ConversationNotificationPolicyNever:
return constants.NotificationNone
case constants.ConversationNotificationPolicyDefault:
fallthrough
case constants.ConversationNotificationPolicyOptIn:
return notificationContentToNotificationType(settings.NotificationContent)
}
}
}
return notificationContentToNotificationType(settings.NotificationContent)
}
return constants.NotificationNone
}
func notificationContentToNotificationType(notificationContent string) constants.NotificationType {
if notificationContent == "NotificationContent.ContactInfo" {
return constants.NotificationConversation
}
return constants.NotificationEvent
}

View File

@ -1,15 +1,17 @@
package utils
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/storage/v1"
"git.openprivacy.ca/cwtch.im/libcwtch-go/constants"
path "path/filepath"
"sync"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/storage/v1"
"encoding/json"
"git.openprivacy.ca/openprivacy/log"
"io/ioutil"
"os"
"path"
"git.openprivacy.ca/openprivacy/log"
)
const (
@ -24,18 +26,38 @@ var lock sync.Mutex
const GlobalSettingsFilename = "ui.globals"
const saltFile = "SALT"
type NotificationPolicy string
const (
NotificationPolicyMute = NotificationPolicy("NotificationPolicy.Mute")
NotificationPolicyOptIn = NotificationPolicy("NotificationPolicy.OptIn")
NotificationPolicyDefaultAll = NotificationPolicy("NotificationPolicy.DefaultAll")
)
type GlobalSettings struct {
Locale string
Theme string
ThemeMode string
PreviousPid int64
ExperimentsEnabled bool
Experiments map[string]bool
BlockUnknownConnections bool
NotificationPolicy NotificationPolicy
NotificationContent string
StreamerMode bool
StateRootPane int
FirstTime bool
UIColumnModePortrait string
UIColumnModeLandscape string
DownloadPath string
AllowAdvancedTorConfig bool
CustomTorrc string
UseCustomTorrc bool
UseExternalTor bool
CustomSocksPort int
CustomControlPort int
UseTorCache bool
TorCacheDir string
}
var DefaultGlobalSettings = GlobalSettings{
@ -43,20 +65,30 @@ var DefaultGlobalSettings = GlobalSettings{
Theme: "dark",
PreviousPid: -1,
ExperimentsEnabled: false,
Experiments: make(map[string]bool),
Experiments: map[string]bool{constants.MessageFormattingExperiment: true},
StateRootPane: 0,
FirstTime: true,
BlockUnknownConnections: false,
StreamerMode: false,
UIColumnModePortrait: "DualpaneMode.Single",
UIColumnModeLandscape: "DualpaneMode.CopyPortrait",
NotificationPolicy: "NotificationPolicy.Mute",
NotificationContent: "NotificationContent.SimpleEvent",
DownloadPath: "",
AllowAdvancedTorConfig: false,
CustomTorrc: "",
UseCustomTorrc: false,
CustomSocksPort: -1,
CustomControlPort: -1,
UseTorCache: false,
TorCacheDir: "",
}
func InitGlobalSettingsFile(directory string, password string) error {
lock.Lock()
defer lock.Unlock()
var key [32]byte
salt, err := ioutil.ReadFile(path.Join(directory, saltFile))
salt, err := os.ReadFile(path.Join(directory, saltFile))
if err != nil {
log.Infof("Could not find salt file: %v (creating a new settings file)", err)
var newSalt [128]byte
@ -66,7 +98,7 @@ func InitGlobalSettingsFile(directory string, password string) error {
return err
}
os.Mkdir(directory, 0700)
err := ioutil.WriteFile(path.Join(directory, saltFile), newSalt[:], 0600)
err := os.WriteFile(path.Join(directory, saltFile), newSalt[:], 0600)
if err != nil {
log.Errorf("Could not write salt file: %v", err)
return err

View File

@ -12,18 +12,18 @@ func RandomProfileImage(onion string) string {
choices := []string{"001-centaur", "002-kraken", "003-dinosaur", "004-tree-1", "005-hand", "006-echidna", "007-robot", "008-mushroom", "009-harpy", "010-phoenix", "011-dragon-1", "012-devil", "013-troll", "014-alien", "015-minotaur", "016-madre-monte", "017-satyr", "018-karakasakozou", "019-pirate", "020-werewolf", "021-scarecrow", "022-valkyrie", "023-curupira", "024-loch-ness-monster", "025-tree", "026-cerberus", "027-gryphon", "028-mermaid", "029-vampire", "030-goblin", "031-yeti", "032-leprechaun", "033-medusa", "034-chimera", "035-elf", "036-hydra", "037-cyclops", "038-pegasus", "039-narwhal", "040-woodcutter", "041-zombie", "042-dragon", "043-frankenstein", "044-witch", "045-fairy", "046-genie", "047-pinocchio", "048-ghost", "049-wizard", "050-unicorn"}
barr, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
if err != nil || len(barr) != 35 {
log.Errorf("error: %v %v %v\n", onion, err, barr)
return "extra/openprivacy.png"
log.Errorf("error finding image for profile: %v %v %v\n", onion, err, barr)
return "assets/extra/openprivacy.png"
}
return "profiles/" + choices[int(barr[33])%len(choices)] + ".png"
return "assets/profiles/" + choices[int(barr[33])%len(choices)] + ".png"
}
func RandomGroupImage(handle string) string {
choices := []string{"001-borobudur", "002-opera-house", "003-burj-al-arab", "004-chrysler", "005-acropolis", "006-empire-state-building", "007-temple", "008-indonesia-1", "009-new-zealand", "010-notre-dame", "011-space-needle", "012-seoul", "013-mosque", "014-milan", "015-statue", "016-pyramid", "017-cologne", "018-brandenburg-gate", "019-berlin-cathedral", "020-hungarian-parliament", "021-buckingham", "022-thailand", "023-independence", "024-angkor-wat", "025-vaticano", "026-christ-the-redeemer", "027-colosseum", "028-golden-gate-bridge", "029-sphinx", "030-statue-of-liberty", "031-cradle-of-humankind", "032-istanbul", "033-london-eye", "034-sagrada-familia", "035-tower-bridge", "036-burj-khalifa", "037-washington", "038-big-ben", "039-stonehenge", "040-white-house", "041-ahu-tongariki", "042-capitol", "043-eiffel-tower", "044-church-of-the-savior-on-spilled-blood", "045-arc-de-triomphe", "046-windmill", "047-louvre", "048-torii-gate", "049-petronas", "050-matsumoto-castle", "051-fuji", "052-temple-of-heaven", "053-pagoda", "054-chichen-itza", "055-forbidden-city", "056-merlion", "057-great-wall-of-china", "058-taj-mahal", "059-pisa", "060-indonesia"}
barr, err := hex.DecodeString(handle)
if err != nil || len(barr) == 0 {
log.Errorf("error: %v %v %v\n", handle, err, barr)
return "extra/openprivacy.png"
log.Errorf("error finding image for group: %v %v %v\n", handle, err, barr)
return "assets/extra/openprivacy.png"
}
return "servers/" + choices[int(barr[0])%len(choices)] + ".png"
return "assets/servers/" + choices[int(barr[0])%len(choices)] + ".png"
}