diff --git a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp index e723526b0..4a80dc272 100644 --- a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp @@ -1,113 +1,136 @@ #include "CommUtilsModule.h" #include "../Tools/Base64.h" +#include "olm/olm.h" #include #include #include namespace comm { using namespace facebook::react; CommUtilsModule::CommUtilsModule(std::shared_ptr jsInvoker) : CommUtilsModuleSchemaCxxSpecJSI(jsInvoker), - utilsThread(std::make_unique("utils")) { + utilsThread(std::make_unique("utils")), + olmUtilityBuffer(::olm_utility_size()) { + this->olmUtility = ::olm_utility(olmUtilityBuffer.data()); } jsi::Value CommUtilsModule::writeBufferToFile( jsi::Runtime &rt, jsi::String path, jsi::Object data) { auto arrayBuffer = data.getArrayBuffer(rt); auto size = arrayBuffer.size(rt); auto dataPtr = arrayBuffer.data(rt); auto filePath = path.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; try { std::ofstream file; file.exceptions(std::fstream::failbit | std::fstream::badbit); file.open(filePath, std::ios::binary); file.write((char *)dataPtr, size); file.close(); } catch (const std::exception &e) { error = "Failed to write file " + filePath + ": " + e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; this->utilsThread->scheduleTask(job); }); } jsi::Value CommUtilsModule::readBufferFromFile(jsi::Runtime &rt, jsi::String path) { auto filePath = path.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::streampos file_size; std::shared_ptr data{nullptr}; try { // Open a file std::ifstream file; file.exceptions(std::fstream::failbit | std::fstream::badbit); file.open(filePath, std::ios::binary); // Get file size std::streampos current_pos = file.tellg(); file.seekg(0, std::ios::end); file_size = file.tellg(); file.seekg(current_pos); // Read file content data = std::shared_ptr{new uint8_t[file_size]}; file.read((char *)data.get(), file_size); file.close(); } catch (const std::exception &e) { error = "Failed to read file " + filePath + ": " + e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto arrayBuffer = innerRt.global() .getPropertyAsFunction(innerRt, "ArrayBuffer") // ArrayBuffer constructor takes one parameter: byte length .callAsConstructor( innerRt, {static_cast(file_size)}) .asObject(innerRt) .getArrayBuffer(innerRt); auto bufferPtr = arrayBuffer.data(innerRt); memcpy((void *)bufferPtr, data.get(), file_size); promise->resolve(std::move(arrayBuffer)); }); }; this->utilsThread->scheduleTask(job); }); } jsi::String CommUtilsModule::base64EncodeBuffer(jsi::Runtime &rt, jsi::Object data) { auto arrayBuffer = data.getArrayBuffer(rt); auto dataPtr = arrayBuffer.data(rt); auto size = arrayBuffer.size(rt); auto bytes = std::vector{dataPtr, dataPtr + size}; auto base64 = Base64::encode(bytes); return jsi::String::createFromUtf8(rt, base64); } +jsi::String CommUtilsModule::sha256(jsi::Runtime &rt, jsi::Object data) { + auto arrayBuffer = data.getArrayBuffer(rt); + auto inputPtr = arrayBuffer.data(rt); + auto inputSize = arrayBuffer.size(rt); + + auto sha256Size = ::olm_sha256_length(this->olmUtility); + OlmBuffer sha256Bytes(sha256Size); + auto outputLength = ::olm_sha256( + this->olmUtility, inputPtr, inputSize, sha256Bytes.data(), sha256Size); + if (outputLength == std::size_t(-1)) { + throw jsi::JSError( + rt, + "olm error: " + + std::string{::olm_utility_last_error(this->olmUtility)}); + } + + std::string sha256String{sha256Bytes.begin(), sha256Bytes.end()}; + return jsi::String::createFromUtf8(rt, sha256String); +} + } // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h index 22cdc81a3..782453a40 100644 --- a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h @@ -1,30 +1,38 @@ #pragma once +#include "../CryptoTools/Tools.h" #include "../Tools/WorkerThread.h" #include "../_generated/utilsJSI.h" +#include "olm/olm.h" #include #include #include +#include namespace comm { namespace jsi = facebook::jsi; +using ::comm::crypto::OlmBuffer; class CommUtilsModule : public facebook::react::CommUtilsModuleSchemaCxxSpecJSI { std::unique_ptr utilsThread; + OlmBuffer olmUtilityBuffer; + ::OlmUtility *olmUtility; + virtual jsi::Value writeBufferToFile( jsi::Runtime &rt, jsi::String path, jsi::Object data) override; virtual jsi::Value readBufferFromFile(jsi::Runtime &rt, jsi::String path) override; virtual jsi::String base64EncodeBuffer(jsi::Runtime &rt, jsi::Object data) override; + virtual jsi::String sha256(jsi::Runtime &rt, jsi::Object data) override; public: CommUtilsModule(std::shared_ptr jsInvoker); }; } // namespace comm diff --git a/native/cpp/CommonCpp/_generated/utilsJSI-generated.cpp b/native/cpp/CommonCpp/_generated/utilsJSI-generated.cpp index bf591d017..71d530618 100644 --- a/native/cpp/CommonCpp/_generated/utilsJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/utilsJSI-generated.cpp @@ -1,34 +1,38 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #include "utilsJSI.h" namespace facebook { namespace react { static jsi::Value __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_writeBufferToFile(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->writeBufferToFile(rt, args[0].asString(rt), args[1].asObject(rt)); } static jsi::Value __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_readBufferFromFile(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->readBufferFromFile(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_base64EncodeBuffer(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->base64EncodeBuffer(rt, args[0].asObject(rt)); } +static jsi::Value __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_sha256(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->sha256(rt, args[0].asObject(rt)); +} CommUtilsModuleSchemaCxxSpecJSI::CommUtilsModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommUtilsTurboModule", jsInvoker) { methodMap_["writeBufferToFile"] = MethodMetadata {2, __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_writeBufferToFile}; methodMap_["readBufferFromFile"] = MethodMetadata {1, __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_readBufferFromFile}; methodMap_["base64EncodeBuffer"] = MethodMetadata {1, __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_base64EncodeBuffer}; + methodMap_["sha256"] = MethodMetadata {1, __hostFunction_CommUtilsModuleSchemaCxxSpecJSI_sha256}; } } // namespace react } // namespace facebook diff --git a/native/cpp/CommonCpp/_generated/utilsJSI.h b/native/cpp/CommonCpp/_generated/utilsJSI.h index 1b53a368b..dba247821 100644 --- a/native/cpp/CommonCpp/_generated/utilsJSI.h +++ b/native/cpp/CommonCpp/_generated/utilsJSI.h @@ -1,80 +1,89 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #pragma once #include #include namespace facebook { namespace react { class JSI_EXPORT CommUtilsModuleSchemaCxxSpecJSI : public TurboModule { protected: CommUtilsModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker); public: virtual jsi::Value writeBufferToFile(jsi::Runtime &rt, jsi::String path, jsi::Object data) = 0; virtual jsi::Value readBufferFromFile(jsi::Runtime &rt, jsi::String path) = 0; virtual jsi::String base64EncodeBuffer(jsi::Runtime &rt, jsi::Object data) = 0; + virtual jsi::String sha256(jsi::Runtime &rt, jsi::Object data) = 0; }; template class JSI_EXPORT CommUtilsModuleSchemaCxxSpec : public TurboModule { public: jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { return delegate_.get(rt, propName); } protected: CommUtilsModuleSchemaCxxSpec(std::shared_ptr jsInvoker) : TurboModule("CommUtilsTurboModule", jsInvoker), delegate_(static_cast(this), jsInvoker) {} private: class Delegate : public CommUtilsModuleSchemaCxxSpecJSI { public: Delegate(T *instance, std::shared_ptr jsInvoker) : CommUtilsModuleSchemaCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} jsi::Value writeBufferToFile(jsi::Runtime &rt, jsi::String path, jsi::Object data) override { static_assert( bridging::getParameterCount(&T::writeBufferToFile) == 3, "Expected writeBufferToFile(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::writeBufferToFile, jsInvoker_, instance_, std::move(path), std::move(data)); } jsi::Value readBufferFromFile(jsi::Runtime &rt, jsi::String path) override { static_assert( bridging::getParameterCount(&T::readBufferFromFile) == 2, "Expected readBufferFromFile(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::readBufferFromFile, jsInvoker_, instance_, std::move(path)); } jsi::String base64EncodeBuffer(jsi::Runtime &rt, jsi::Object data) override { static_assert( bridging::getParameterCount(&T::base64EncodeBuffer) == 2, "Expected base64EncodeBuffer(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::base64EncodeBuffer, jsInvoker_, instance_, std::move(data)); } + jsi::String sha256(jsi::Runtime &rt, jsi::Object data) override { + static_assert( + bridging::getParameterCount(&T::sha256) == 2, + "Expected sha256(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::sha256, jsInvoker_, instance_, std::move(data)); + } private: T *instance_; }; Delegate delegate_; }; } // namespace react } // namespace facebook diff --git a/native/schema/CommUtilsModuleSchema.js b/native/schema/CommUtilsModuleSchema.js index da3de7995..4754a214d 100644 --- a/native/schema/CommUtilsModuleSchema.js +++ b/native/schema/CommUtilsModuleSchema.js @@ -1,26 +1,29 @@ // @flow 'use strict'; import { TurboModuleRegistry } from 'react-native'; import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport.js'; // codegen doesn't understand ArrayBuffers, so we need to map them to Objects type JSIArrayBuffer = Object; interface Spec extends TurboModule { // filesystem utils +writeBufferToFile: (path: string, data: JSIArrayBuffer) => Promise; +readBufferFromFile: (path: string) => Promise; +base64EncodeBuffer: (data: JSIArrayBuffer) => string; + // crypto utils + +sha256: (data: JSIArrayBuffer) => string; } // for public interface, we use the correct types export interface UtilsModuleSpec { +writeBufferToFile: (path: string, data: ArrayBuffer) => Promise; +readBufferFromFile: (path: string) => Promise; +base64EncodeBuffer: (data: ArrayBuffer) => string; + +sha256: (data: ArrayBuffer) => string; } export default (TurboModuleRegistry.getEnforcing( 'CommUtilsTurboModule', ): Spec);