diff --git a/.drone.yml b/.drone.yml index 45fc462b..f84cb7b9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -24,7 +24,7 @@ steps: - git checkout $DRONE_COMMIT - name: fetch - image: cirrusci/flutter:dev + image: cirrusci/flutter:2.5.0-6.0.pre volumes: - name: deps path: /root/.pub-cache @@ -47,7 +47,7 @@ steps: # #Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting - name: build-linux - image: openpriv/flutter-desktop:linux-dev + image: openpriv/flutter-desktop:linux-fdev2.5rc volumes: - name: deps path: /root/.pub-cache @@ -61,7 +61,7 @@ steps: - rm -r cwtch - name: test-build-android - image: cirrusci/flutter:dev + image: cirrusci/flutter:2.5.0-6.0.pre when: event: pull_request volumes: @@ -71,7 +71,7 @@ steps: - flutter build apk --debug - name: build-android - image: cirrusci/flutter:dev + image: cirrusci/flutter:2.5.0-6.0.pre when: event: push environment: @@ -95,7 +95,7 @@ steps: #- cp build/app/outputs/flutter-apk/app-debug.apk deploy/android - name: widget-tests - image: cirrusci/flutter:dev + image: cirrusci/flutter:2.5.0-6.0.pre volumes: - name: deps path: /root/.pub-cache @@ -126,7 +126,7 @@ steps: - mv ./../sha256s.txt . - cd .. # TODO: do deployment once files actaully compile - - scp -r -o StrictHostKeyChecking=no -i ~/id_rsa $DIR buildfiles@openprivacy.ca:/home/buildfiles/buildfiles/ + - scp -r -o StrictHostKeyChecking=no -i ~/id_rsa $DIR buildfiles@build.openprivacy.ca:/home/buildfiles/buildfiles/ - name: notify-email image: drillster/drone-email @@ -175,7 +175,7 @@ clone: steps: - name: clone - image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc + image: openpriv/flutter-desktop:windows-sdk30-fdev2.5rc environment: buildbot_key_b64: from_secret: buildbot_key_b64 @@ -193,16 +193,16 @@ steps: - git checkout $Env:DRONE_COMMIT - name: fetch - image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc + image: openpriv/flutter-desktop:windows-sdk30-fdev2.5rc commands: - - powershell -command "Invoke-WebRequest -Uri https://dist.torproject.org/torbrowser/10.5a17/tor-win64-0.4.6.5.zip -OutFile tor.zip" + - powershell -command "Invoke-WebRequest -Uri https://git.openprivacy.ca/openprivacy/buildfiles/raw/branch/master/tor/tor-win64-0.4.6.5.zip -OutFile tor.zip" - powershell -command "if ((Get-FileHash tor.zip -Algorithm sha512).Hash -ne '7917561a7a063440a1ddfa9cb544ab9ffd09de84cea3dd66e3cc9cd349dd9f85b74a522ec390d7a974bc19b424c4d53af60e57bbc47e763d13cab6a203c4592f' ) { Write-Error 'tor.zip sha512sum mismatch' }" - git describe --tags --abbrev=1 > VERSION - powershell -command "Get-Date -Format 'yyyy-MM-dd-HH-mm'" > BUILDDATE - .\fetch-libcwtch-go.ps1 - name: build-windows - image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc + image: openpriv/flutter-desktop:windows-sdk30-fdev2.5rc commands: - flutter pub get - $Env:version += type .\VERSION @@ -213,9 +213,9 @@ steps: # flutter hasn't worked out it's packaging of required dll's so we have to resort to this manual nonsense # https://github.com/google/flutter-desktop-embedding/issues/587 # https://github.com/flutter/flutter/issues/53167 - - copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140.dll $Env:releasedir - - copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:releasedir - - copy C:\BuildTools\VC\Redist\MSVC\14.29.30036\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:releasedir + - copy C:\BuildTools\VC\Redist\MSVC\14.29.30133\x64\Microsoft.VC142.CRT\vcruntime140.dll $Env:releasedir + - copy C:\BuildTools\VC\Redist\MSVC\14.29.30133\x64\Microsoft.VC142.CRT\vcruntime140_1.dll $Env:releasedir + - copy C:\BuildTools\VC\Redist\MSVC\14.29.30133\x64\Microsoft.VC142.CRT\msvcp140.dll $Env:releasedir - copy README.md $Env:releasedir\ - copy windows\*.bat $Env:releasedir\ - powershell -command "Expand-Archive -Path tor.zip -DestinationPath $Env:releasedir\Tor" @@ -258,7 +258,7 @@ steps: - move *.sha512 deploy\$Env:builddir - name: deploy-windows - image: openpriv/flutter-desktop:windows-sdk30-fdev2.3rc + image: openpriv/flutter-desktop:windows-sdk30-fdev2.5rc when: event: push status: [ success ] @@ -268,7 +268,7 @@ steps: commands: - echo $Env:BUILDFILES_KEY > id_rsab64 - certutil -decode id_rsab64 id_rsa - - scp -r -o StrictHostKeyChecking=no -i id_rsa deploy\\* buildfiles@openprivacy.ca:/home/buildfiles/buildfiles/ + - scp -r -o StrictHostKeyChecking=no -i id_rsa deploy\\* buildfiles@build.openprivacy.ca:/home/buildfiles/buildfiles/ trigger: repo: cwtch.im/cwtch-ui diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index f4a93cec..81b6e224 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -v1.1.0-2021-07-15-19-15 +v1.1.1-16-g7376218-2021-08-25-16-54 diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index f0957f08..6c5d4802 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'dart:isolate'; import 'dart:io' show Platform; import 'package:cwtch/cwtch/cwtchNotifier.dart'; -import 'package:flutter/src/services/text_input.dart'; import 'package:path/path.dart' as path; import 'package:ffi/ffi.dart'; @@ -22,6 +21,9 @@ typedef StartCwtchFn = int Function(Pointer dir, int len, Pointer to typedef void_from_void_funtion = Void Function(); typedef VoidFromVoidFunction = void Function(); +typedef free_function = Void Function(Pointer); +typedef FreeFn = void Function(Pointer); + typedef void_from_string_string_function = Void Function(Pointer, Int32, Pointer, Int32); typedef VoidFromStringStringFn = void Function(Pointer, int, Pointer, int); @@ -34,25 +36,15 @@ typedef VoidFromStringStringStringStringFn = void Function(Pointer, int, P typedef void_from_string_string_int_int_function = Void Function(Pointer, Int32, Pointer, Int32, Int64, Int64); typedef VoidFromStringStringIntIntFn = void Function(Pointer, int, Pointer, int, int, int); -typedef access_cwtch_eventbus_function = Void Function(); -typedef NextEventFn = void Function(); - typedef string_to_void_function = Void Function(Pointer str, Int32 length); typedef StringFn = void Function(Pointer dir, int); typedef string_string_to_void_function = Void Function(Pointer str, Int32 length, Pointer str2, Int32 length2); typedef StringStringFn = void Function(Pointer, int, Pointer, int); -typedef get_json_blob_void_function = Pointer Function(); -typedef GetJsonBlobVoidFn = Pointer Function(); - typedef get_json_blob_string_function = Pointer Function(Pointer str, Int32 length); typedef GetJsonBlobStringFn = Pointer Function(Pointer str, int len); -//func NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) { -typedef get_int_from_str_str_function = Int32 Function(Pointer, Int32, Pointer, Int32); -typedef GetIntFromStrStrFn = int Function(Pointer, int, Pointer, int); - //func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char { typedef get_json_blob_from_str_str_int_function = Pointer Function(Pointer, Int32, Pointer, Int32, Int32); typedef GetJsonBlobFromStrStrIntFn = Pointer Function(Pointer, int, Pointer, int, int); @@ -138,9 +130,7 @@ class CwtchFfi implements Cwtch { // Called on object being disposed to (presumably on app close) to close the isolate that's listening to libcwtch-go events @override void dispose() { - if (cwtchIsolate != null) { - cwtchIsolate.kill(priority: Isolate.immediate); - } + cwtchIsolate.kill(priority: Isolate.immediate); } // Entry point for an isolate to listen to a stream of events pulled from libcwtch-go and return them on the sendPort @@ -165,9 +155,21 @@ class CwtchFfi implements Cwtch { // ignore: non_constant_identifier_names final GetAppbusEvent = getAppbusEventC.asFunction(); - while (true) { + // Embedded Version of _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved + var free = library.lookup>("c_FreePointer"); + final Free = free.asFunction(); + + // ignore: non_constant_identifier_names + final GetAppBusEvent = () { + // ignore: non_constant_identifier_names Pointer result = GetAppbusEvent(); String event = result.toDartString(); + Free(result); + return event; + }; + + while (true) { + final event = GetAppBusEvent(); if (event.startsWith("{\"EventType\":\"Shutdown\"")) { print("Shutting down isolate thread: $event"); @@ -184,6 +186,7 @@ class CwtchFfi implements Cwtch { final SelectProfile = selectProfileC.asFunction(); final ut8Onion = onion.toNativeUtf8(); SelectProfile(ut8Onion, ut8Onion.length); + malloc.free(ut8Onion); } // ignore: non_constant_identifier_names @@ -194,6 +197,8 @@ class CwtchFfi implements Cwtch { final utf8nick = nick.toNativeUtf8(); final ut8pass = pass.toNativeUtf8(); CreateProfile(utf8nick, utf8nick.length, ut8pass, ut8pass.length); + malloc.free(utf8nick); + malloc.free(ut8pass); } // ignore: non_constant_identifier_names @@ -203,6 +208,7 @@ class CwtchFfi implements Cwtch { final LoadProfiles = loadProfileC.asFunction(); final ut8pass = pass.toNativeUtf8(); LoadProfiles(ut8pass, ut8pass.length); + malloc.free(ut8pass); } // ignore: non_constant_identifier_names @@ -214,6 +220,9 @@ class CwtchFfi implements Cwtch { final utf8handle = handle.toNativeUtf8(); Pointer jsonMessageBytes = GetMessage(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index); String jsonMessage = jsonMessageBytes.toDartString(); + _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes); + malloc.free(utf8profile); + malloc.free(utf8handle); return jsonMessage; } @@ -226,6 +235,8 @@ class CwtchFfi implements Cwtch { final utf8onion = onion.toNativeUtf8(); final utf8json = json.toNativeUtf8(); SendAppBusEvent(utf8onion, utf8onion.length, utf8json, utf8json.length); + malloc.free(utf8onion); + malloc.free(utf8json); } @override @@ -236,6 +247,7 @@ class CwtchFfi implements Cwtch { final SendAppBusEvent = sendAppBusEvent.asFunction(); final utf8json = json.toNativeUtf8(); SendAppBusEvent(utf8json, utf8json.length); + malloc.free(utf8json); } @override @@ -247,6 +259,8 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8(); AcceptContact(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override @@ -258,6 +272,8 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = contactHandle.toNativeUtf8(); BlockContact(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override @@ -270,6 +286,9 @@ class CwtchFfi implements Cwtch { final u2 = contactHandle.toNativeUtf8(); final u3 = message.toNativeUtf8(); SendMessage(u1, u1.length, u2, u2.length, u3, u3.length); + malloc.free(u1); + malloc.free(u2); + malloc.free(u3); } @override @@ -282,6 +301,9 @@ class CwtchFfi implements Cwtch { final u2 = contactHandle.toNativeUtf8(); final u3 = target.toNativeUtf8(); SendInvitation(u1, u1.length, u2, u2.length, u3, u3.length); + malloc.free(u1); + malloc.free(u2); + malloc.free(u3); } @override @@ -302,6 +324,8 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = bundle.toNativeUtf8(); ImportBundle(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override @@ -315,6 +339,10 @@ class CwtchFfi implements Cwtch { final u3 = key.toNativeUtf8(); final u4 = value.toNativeUtf8(); SetGroupAttribute(u1, u1.length, u2, u2.length, u3, u3.length, u4, u4.length); + malloc.free(u1); + malloc.free(u2); + malloc.free(u3); + malloc.free(u4); } @override @@ -326,9 +354,12 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = groupHandle.toNativeUtf8(); RejectInvite(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override + // ignore: non_constant_identifier_names void CreateGroup(String profileOnion, String server, String groupName) { var createGroup = library.lookup>("c_CreateGroup"); // ignore: non_constant_identifier_names @@ -337,6 +368,10 @@ class CwtchFfi implements Cwtch { final u2 = server.toNativeUtf8(); final u3 = groupName.toNativeUtf8(); CreateGroup(u1, u1.length, u2, u2.length, u3, u3.length); + + malloc.free(u1); + malloc.free(u2); + malloc.free(u3); } @override @@ -348,6 +383,8 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = handle.toNativeUtf8(); LeaveConversation(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override @@ -359,9 +396,12 @@ class CwtchFfi implements Cwtch { final u1 = profileOnion.toNativeUtf8(); final u2 = groupHandle.toNativeUtf8(); LeaveGroup(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override + // ignore: non_constant_identifier_names void UpdateMessageFlags(String profile, String handle, int index, int flags) { var updateMessageFlagsC = library.lookup>("c_UpdateMessageFlags"); // ignore: non_constant_identifier_names @@ -369,6 +409,8 @@ class CwtchFfi implements Cwtch { final utf8profile = profile.toNativeUtf8(); final utf8handle = handle.toNativeUtf8(); updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags); + malloc.free(utf8profile); + malloc.free(utf8handle); } @override @@ -380,14 +422,18 @@ class CwtchFfi implements Cwtch { final u1 = onion.toNativeUtf8(); final u2 = currentPassword.toNativeUtf8(); DeleteProfile(u1, u1.length, u2, u2.length); + malloc.free(u1); + malloc.free(u2); } @override + // ignore: non_constant_identifier_names Future Shutdown() async { var shutdown = library.lookup>("c_ShutdownCwtch"); // ignore: non_constant_identifier_names // Shutdown Cwtch + Tor... + // ignore: non_constant_identifier_names final Shutdown = shutdown.asFunction(); Shutdown(); @@ -400,6 +446,7 @@ class CwtchFfi implements Cwtch { } @override + // ignore: non_constant_identifier_names Future GetMessageByContentHash(String profile, String handle, String contentHash) async { var getMessagesByContentHashC = library.lookup>("c_GetMessagesByContentHash"); // ignore: non_constant_identifier_names @@ -409,6 +456,20 @@ class CwtchFfi implements Cwtch { final utf8contentHash = contentHash.toNativeUtf8(); Pointer jsonMessageBytes = GetMessagesByContentHash(utf8profile, utf8profile.length, utf8handle, utf8handle.length, utf8contentHash, utf8contentHash.length); String jsonMessage = jsonMessageBytes.toDartString(); + + _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(jsonMessageBytes); + malloc.free(utf8profile); + malloc.free(utf8handle); + malloc.free(utf8contentHash); return jsonMessage; } + + // ignore: non_constant_identifier_names + // Incredibly dangerous function which invokes a free in libCwtch, should only be used + // as documented in `MEMORY.md` in libCwtch repo. + void _UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(Pointer ptr) { + var free = library.lookup>("c_FreePointer"); + final Free = free.asFunction(); + Free(ptr); + } } diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 8d0509cc..91e576ac 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -217,6 +217,7 @@ class _MessageViewState extends State { autofocus: !Platform.isAndroid, textInputAction: TextInputAction.newline, keyboardType: TextInputType.multiline, + enableIMEPersonalizedLearning: false, minLines: 1, maxLines: null, onFieldSubmitted: _sendMessage, diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index e7483361..46e88796 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -37,6 +37,7 @@ class _CwtchButtonTextFieldState extends State { readOnly: widget.readonly, showCursor: !widget.readonly, focusNode: _focusNode, + enableIMEPersonalizedLearning: false, decoration: InputDecoration( suffixIcon: IconButton( onPressed: widget.onPressed, diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 18c750dc..140e3703 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cwtch/views/contactsview.dart'; import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; @@ -127,9 +129,9 @@ class _ContactRowState extends State { } // If the last message was over a day ago, just state the date if (DateTime.now().difference(date).inDays > 1) { - return DateFormat.yMd().format(date.toLocal()); + return DateFormat.yMd(Platform.localeName).format(date.toLocal()); } // Otherwise just state the time. - return DateFormat.Hm().format(date.toLocal()); + return DateFormat.Hm(Platform.localeName).format(date.toLocal()); } } diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 4770283d..9214fd69 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/message.dart'; @@ -39,7 +40,7 @@ class InvitationBubbleState extends State { var borderRadiousEh = 15.0; var showGroupInvite = Provider.of(context).isExperimentEnabled(TapirGroupsExperiment); rejected = Provider.of(context).flags & 0x01 == 0x01; - var prettyDate = DateFormat.yMd().add_jm().format(Provider.of(context).timestamp); + var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of(context).timestamp); // If the sender is not us, then we want to give them a nickname... var senderDisplayStr = ""; diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index 094e0ff9..2ba8fe0c 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cwtch/models/message.dart'; import 'package:cwtch/widgets/malformedbubble.dart'; import 'package:flutter/material.dart'; @@ -28,7 +30,7 @@ class MessageBubbleState extends State { // var myKey = Provider.of(context).profileOnion + "::" + Provider.of(context).contactHandle + "::" + Provider.of(context).messageIndex.toString(); DateTime messageDate = Provider.of(context).timestamp; - prettyDate = DateFormat.yMd().add_jm().format(messageDate.toLocal()); + prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(messageDate.toLocal()); // If the sender is not us, then we want to give them a nickname... var senderDisplayStr = ""; diff --git a/lib/widgets/passwordfield.dart b/lib/widgets/passwordfield.dart index 4cf061b8..acd79787 100644 --- a/lib/widgets/passwordfield.dart +++ b/lib/widgets/passwordfield.dart @@ -37,6 +37,7 @@ class _CwtchTextFieldState extends State { controller: widget.controller, validator: widget.validator, obscureText: obscureText, + enableIMEPersonalizedLearning: false, autofillHints: widget.autoFillHints, autovalidateMode: AutovalidateMode.always, onFieldSubmitted: widget.action, diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index c1be445d..64b4f020 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -39,6 +39,7 @@ class _CwtchTextFieldState extends State { validator: widget.validator, onChanged: widget.onChanged, autofocus: widget.autofocus, + enableIMEPersonalizedLearning: false, focusNode: _focusNode, decoration: InputDecoration( labelText: widget.labelText, diff --git a/pubspec.lock b/pubspec.lock index 2ee3b476..b8117b89 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.7.0" + version: "2.8.1" boolean_selector: dependency: transitive description: @@ -181,7 +181,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.7.0" msix: dependency: "direct dev" description: @@ -329,6 +329,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.0.0" + scrollable_positioned_list: + dependency: "direct main" + description: + name: scrollable_positioned_list + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0-nullsafety.0" sky_engine: dependency: transitive description: flutter @@ -375,7 +382,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.1" + version: "0.4.2" typed_data: dependency: transitive description: