Browse Source

Allow CryptoLib4Pascal - Core

CryptoLib4Pascal is automatically selected on config.inc file (currently only on Android/MAC/IOS devices)
For testing purposes can be forced manually
Pascal Coin 6 years ago
parent
commit
fc6e14db34

+ 46 - 24
src/config.inc

@@ -13,27 +13,41 @@
   PascalCoin configuration file to build
   **************************************
 
-  Choose ONLY ONE of directives:
+  Compiler directives definitions:
+  
+  NOTE: By default, only need to choose "TESTNET" or "PRODUCTION", all other directives are automatically selected
 
-    CHANGES ON 2.1.10 and V3: OpenSSL must be version 1.1
-	
-    OPTIONS_BY_DEFAULT:
-      In Delphi = Synapse + OpenSSL v1.1
-      In FPC = Synapse + OpenSSL v1.1
-    DelphiSockets_OpenSSLv10
-    Synapse_OpenSSLv10
-    Synapse_OpenSSLv11
+  - TESTNET                 : Will compile a TESTNET version
+  - PRODUCTION              : Will compile a PRODUCTION (Main Net) version
+  
+  ( User does not need to define/undefine next values )
+  
+  - Use_CryptoLib4Pascal    : Will not use OpenSSL library, will use pascal native CryptoLib4Pascal
+  - Use_OpenSSL             : Will use OpenSSL library (Need version 1.1)
+  - OpenSSL10               : When "Use_OpenSSL" enabled, will use version 1.0 instead of 1.1 -> DO NOT USE!
+  
+  - Synapse                 : Will use Synapse sockets (Preferred)
+  - DelphiSockets           : Will use Delphi Indy sockets (Use only for special purposes... for example for mobile apps)
+  
+  - OPTIONS_BY_DEFAULT      : (Preferred)
+      Will define "Synapse" and will undefine "OpenSSL10"
+  - DelphiSockets_OpenSSLv10 :
+      Will define "DelphiSockets" and will define "OpenSSL10"
+  - Synapse_OpenSSLv10      :
+      Will define "Synapse" and will define "OpenSSL10"
+  - Synapse_OpenSSLv11      :
+      Will define "Synapse" and will undefine "OpenSSL10" 
 
 }
 
+  {.$DEFINE PRODUCTION}
+  {$DEFINE TESTNET}
+
   {$DEFINE OPTIONS_BY_DEFAULT}
   {.$DEFINE DelphiSockets_OpenSSLv10}
   {.$DEFINE Synapse_OpenSSLv10}
   {.$DEFINE Synapse_OpenSSLv11}
 
-  {.$DEFINE PRODUCTION}
-  {$DEFINE TESTNET}
-
   // Used to activate RandomHash in V4 hard-fork
   {$DEFINE ACTIVATE_RANDOMHASH_V4}
 
@@ -67,13 +81,14 @@ ERROR: You must select ONLY ONE option: PRODUCTION or TESTNET
 ERROR: You must select ONE option!
 {$ENDIF}{$ENDIF}{$ENDIF}{$ENDIF}
 {$IFDEF OPTIONS_BY_DEFAULT}
+  {$DEFINE Use_OpenSSL}
   // By default are: Synapse + OpenSSLv11
   {$IFDEF ANDROID} 
     // Android usage (on Delphi) does not use Synapse
-	{$UNDEF Synapse}
-	{$DEFINE DelphiSockets}
+    {$UNDEF Synapse}
+    {$DEFINE DelphiSockets}
   {$ELSE}
-	{$DEFINE Synapse}
+    {$DEFINE Synapse}
   {$ENDIF}
   {$UNDEF OpenSSL10}
   {$IFDEF DelphiSockets_OpenSSLv10}ERROR: You selected more than 1 option{$ENDIF}
@@ -105,6 +120,22 @@ ERROR: You must select ONE option!
   {$ENDIF}
 {$ENDIF}
 
+{$ifNdef FPC}
+  // We are on Delphi compiler
+  {$IF Defined(ANDROID) or Defined(MACOS) or Defined(IOS) }
+    // On Delphi and Android/IOS/MAC environment, AnsiString is not available and use DelphiSockets instead of Synapse
+    {$DEFINE NO_ANSISTRING}
+    {$UNDEF OpenSSL10}
+    {$UNDEF Use_OpenSSL}
+    {$DEFINE Use_CryptoLib4Pascal}
+    {$UNDEF Synapse}
+    {$DEFINE DelphiSockets}
+  {$ELSE}
+    {$UNDEF NO_ANSISTRING}
+  {$ENDIF}
+{$ENDIF}
+
+
 {$IFDEF OpenSSL10}
   ERROR: OpenSLL v1.0 is not longer valid, use OpenSSL v1.1 instead
 {$ENDIF}
@@ -114,12 +145,3 @@ ERROR: You must select ONE option!
 {$ENDIF}
 {$ENDIF}
 
-{$ifNdef FPC}
-  // We are on Delphi compiler
-  {$ifdef ANDROID}
-    // On Delphi and Android environment, AnsiString is not available
-    {$DEFINE NO_ANSISTRING}
-  {$ELSE}
-    {$UNDEF NO_ANSISTRING}
-  {$ENDIF}
-{$ENDIF}

+ 5 - 0
src/core/UAES.pas

@@ -29,6 +29,11 @@ unit UAES;
 {$ENDIF}
 
 {$I config.inc}
+
+{$IF not Defined(Use_OpenSSL)}
+  {$Message Warn 'ERROR: Use_OpenSSL is not defined, you should not use this UNIT!'}
+{$ENDIF}
+
 interface
 
 uses

+ 4 - 8
src/core/UAccounts.pas

@@ -477,7 +477,7 @@ Procedure Check_Safebox_Integrity(sb : TPCSafebox; title: String);
 implementation
 
 uses
-  ULog, UOpenSSLdef, UOpenSSL, UAccountKeyStorage, math, UCommon;
+  ULog, UAccountKeyStorage, math, UCommon;
 
 { This function is for testing purpose only.
   Will check if Account Names are well assigned and stored }
@@ -1374,16 +1374,12 @@ begin
   errors := '';
   case account.EC_OpenSSL_NID of
     CT_NID_secp256k1,CT_NID_secp384r1,CT_NID_sect283k1,CT_NID_secp521r1 : begin
-      Result := TECPrivateKey.IsValidPublicKey(account);
-      if Not Result then begin
-        errors := Format('Invalid AccountKey type:%d - Length x:%d y:%d Error:%s',[account.EC_OpenSSL_NID,length(account.x),length(account.y),  ERR_error_string(ERR_get_error(),nil)]);
-      end;
+      Result := TECPrivateKey.IsValidPublicKey(account,errors);
     end;
   else
     errors := Format('Invalid AccountKey type:%d (Unknown type) - Length x:%d y:%d',[account.EC_OpenSSL_NID,length(account.x),length(account.y)]);
     Result := False;
   end;
-  if (errors='') And (Not Result) then errors := ERR_error_string(ERR_get_error(),nil);
 end;
 
 class function TAccountComp.PrivateToAccountkey(key: TECPrivateKey): TAccountKey;
@@ -3237,9 +3233,9 @@ class function TPCSafeBox.ValidAccountName(const new_name: TRawBytes; var errors
     This function is case senstive, and only lower case chars are valid.
     Execute a LowerCase() prior to call this function!
     }
-Const CT_PascalCoin_Base64_Charset : ShortString = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+{}[]\_:"|<>,.?/~';
+Const CT_PascalCoin_Base64_Charset : RawByteString = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+{}[]\_:"|<>,.?/~';
       // First char can't start with a number
-      CT_PascalCoin_FirstChar_Charset : ShortString = 'abcdefghijklmnopqrstuvwxyz!@#$%^&*()-+{}[]\_:"|<>,.?/~';
+      CT_PascalCoin_FirstChar_Charset : RawByteString = 'abcdefghijklmnopqrstuvwxyz!@#$%^&*()-+{}[]\_:"|<>,.?/~';
       CT_PascalCoin_name_min_length = 3;
       CT_PascalCoin_name_max_length = 64;
 var i,j : Integer;

+ 1 - 0
src/core/UBlockChain.pas

@@ -3367,3 +3367,4 @@ initialization
 finalization
   FreeAndNil(_PCOperationsStorage);
 end.
+

File diff suppressed because it is too large
+ 363 - 135
src/core/UCrypto.pas


+ 4 - 0
src/core/UECIES.pas

@@ -41,6 +41,10 @@ unit UECIES;
 
 {$I config.inc}
 
+{$IF not Defined(Use_OpenSSL)}
+  {$Message Warn 'ERROR: Use_OpenSSL is not defined, you should not use this UNIT!'}
+{$ENDIF}
+
 interface
 
 Uses UOpenSSL, UCrypto, ULog, UConst, UBaseTypes, UPCDataTypes;

+ 1 - 1
src/core/UNetProtection.pas

@@ -172,7 +172,7 @@ begin
   begin
     I := (L + H) shr 1;
     PN := lockedList.Items[I];
-    C := CompareStr( PN.ip, ip );
+    C := CompareStr( PN^.ip, ip );
     if C < 0 then L := I + 1 else
     begin
       H := I - 1;

+ 3 - 3
src/core/UNetProtocol.pas

@@ -498,7 +498,7 @@ Const
 implementation
 
 uses
-  UConst, ULog, UNode, UTime, UECIES, UChunk;
+  UConst, ULog, UNode, UTime, UPCEncryption, UChunk;
 
 Const
   CT_NetTransferType : Array[TNetTransferType] of String = ('Unknown','Request','Response','Autosend');
@@ -3607,7 +3607,7 @@ begin
       errors := 'Invalid message data';
       exit;
     end;
-    If Not ECIESDecrypt(TNetData.NetData.FNodePrivateKey.EC_OpenSSL_NID,TNetData.NetData.FNodePrivateKey.PrivateKey,false,messagecrypted,decrypted) then begin
+    if not TPCEncryption.DoPascalCoinECIESDecrypt(TNetData.NetData.NodePrivateKey.PrivateKey,messagecrypted,decrypted) then begin
       errors := 'Error on decrypting message';
       exit;
     end;
@@ -4392,7 +4392,7 @@ begin
   data := TMemoryStream.Create;
   Try
     // Cypher message:
-    cyp := ECIESEncrypt(FClientPublicKey,TEncoding.ASCII.GetBytes(TheMessage));
+    TPCEncryption.DoPascalCoinECIESEncrypt(FClientPublicKey,TEncoding.ASCII.GetBytes(TheMessage),cyp);
     TStreamOp.WriteAnsiString(data,cyp);
     Send(ntp_autosend,CT_NetOp_Message,0,0,data);
     Result := true;

+ 6 - 0
src/core/UPCDataTypes.pas

@@ -27,6 +27,12 @@ uses
 
 type
 
+  TECPrivateKeyInfo = record
+    EC_OpenSSL_NID : Word;
+    EC_KEY_Ptr : Pointer;    // Used when compiled with $DEFINE Use_OpenSSL
+    RAW_PrivKey : TRawBytes; // Used when compiled with $DEFINE Use_CryptoLib4Pascal
+  end;
+
   { TECDSA_Public is a public key information }
   TECDSA_Public = record
      EC_OpenSSL_NID : Word;

+ 3 - 3
src/core/UPoolMining.pas

@@ -22,17 +22,17 @@ unit UPoolMining;
 
 interface
 
+{$I config.inc}
+
 Uses
 {$IFnDEF FPC}
   Windows,
 {$ELSE}
   {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
-  UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UAES, UNode,
+  UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UPCEncryption, UNode,
   UCrypto, UAccounts, UConst, UBlockChain, UBaseTypes;
 
-{$I config.inc}
-
 Const
   CT_PoolMining_Method_STATUS = 'status';
   CT_PoolMining_Method_MINER_NOTIFY = 'miner-notify'; // Server message to clients to update miners PoW data

+ 11 - 9
src/core/URPC.pas

@@ -22,8 +22,10 @@ unit URPC;
 
 interface
 
+{$I config.inc}
+
 Uses UThread, ULog, UConst, UNode, UAccounts, UCrypto, UBlockChain,
-  UNetProtocol, UOpTransaction, UWallet, UTime, UAES, UECIES, UTxMultiOperation,
+  UNetProtocol, UOpTransaction, UWallet, UTime, UPCEncryption, UTxMultiOperation,
   UJSONFunctions, classes, blcksock, synsock,
   IniFiles, Variants, math, UBaseTypes, UOpenSSL,
   UPCOrderedLists, UPCDataTypes,
@@ -934,11 +936,11 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     if (length(RawPayload)>0) then begin
       if (Payload_method='none') then EncodedRAWPayload:=RawPayload
       else if (Payload_method='dest') then begin
-        EncodedRAWPayload := ECIESEncrypt(targetAccountKey,RawPayload);
+        TPCEncryption.DoPascalCoinECIESEncrypt(targetAccountKey,RawPayload,EncodedRAWPayload);
       end else if (Payload_method='sender') then begin
-        EncodedRAWPayload := ECIESEncrypt(senderAccounKey,RawPayload);
+        TPCEncryption.DoPascalCoinECIESEncrypt(senderAccounKey,RawPayload,EncodedRAWPayload);
       end else if (Payload_method='aes') then begin
-        EncodedRAWPayload := TAESComp.EVP_Encrypt_AES256(RawPayload,TEncoding.ANSI.GetBytes(EncodePwdForAES));
+        EncodedRAWPayload := TPCEncryption.DoPascalCoinAESEncrypt(RawPayload,TEncoding.ANSI.GetBytes(EncodePwdForAES));
       end else begin
         ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
         ErrorDesc:='Invalid encode payload method: '+Payload_method;
@@ -1388,9 +1390,9 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     if (length(RawPayload)>0) then begin
       if (Payload_method='none') then f_raw:=RawPayload
       else if (Payload_method='pubkey') then begin
-        f_raw := ECIESEncrypt(pub_key,RawPayload);
+        TPCEncryption.DoPascalCoinECIESEncrypt(pub_key,RawPayload,f_raw);
       end else if (Payload_method='aes') then begin
-        f_raw := TAESComp.EVP_Encrypt_AES256(RawPayload,TEncoding.ANSI.GetBytes(EncodePwdForAES));
+        f_raw := TPCEncryption.DoPascalCoinAESEncrypt(RawPayload,TEncoding.ANSI.GetBytes(EncodePwdForAES));
       end else begin
         ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
         ErrorDesc:='Invalid encode payload method: '+Payload_method;
@@ -1416,7 +1418,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     for i := 0 to _RPCServer.WalletKeys.Count - 1 do begin
       pkey := _RPCServer.WalletKeys.Key[i].PrivateKey;
       if (assigned(pkey)) then begin
-        If ECIESDecrypt(pkey.EC_OpenSSL_NID,pkey.PrivateKey,false,RawEncryptedPayload,decrypted_payload) then begin
+        if TPCEncryption.DoPascalCoinECIESDecrypt(pkey.PrivateKey,RawEncryptedPayload,decrypted_payload) then begin
           GetResultObject.GetAsVariant('result').Value:= true;
           GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
           GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;
@@ -1424,12 +1426,12 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           GetResultObject.GetAsVariant('payload_method').Value:= 'key';
           GetResultObject.GetAsVariant('enc_pubkey').Value:= TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pkey.PublicKey));
           Result := true;
-          exit;
+          Exit;
         end;
       end;
     end;
     for i := 0 to jsonArrayPwds.Count - 1 do begin
-      if TAESComp.EVP_Decrypt_AES256(RawEncryptedPayload,jsonArrayPwds.GetAsVariant(i).AsString(''),decrypted_payload) then begin
+      if TPCEncryption.DoPascalCoinAESDecrypt(RawEncryptedPayload,TEncoding.ANSI.GetBytes(jsonArrayPwds.GetAsVariant(i).AsString('')),decrypted_payload) then begin
         GetResultObject.GetAsVariant('result').Value:= true;
         GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
         GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;

+ 2 - 0
src/core/UThread.pas

@@ -24,7 +24,9 @@ interface
 
 uses
 {$IFnDEF FPC}
+  {$IFDEF WINDOWS}
   Windows,
+  {$ENDIF}
 {$ELSE}
   {$IFDEF LINUX}cthreads,{$ENDIF}
 {$ENDIF}

+ 4 - 4
src/core/UTxMultiOperation.pas

@@ -149,7 +149,7 @@ Type
     Function IndexOfAccountReceiver(nAccount : Cardinal; startPos : Integer) : Integer;
     Function IndexOfAccountChanger(nAccount : Cardinal) : Integer; overload;
     class Function IndexOfAccountChanger(nAccount : Cardinal; startPos : Integer; const changesInfo : TMultiOpChangesInfo) : Integer; overload;
-    class Function OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes : TOpChangeAccountInfoTypes) : AnsiString;
+    class Function OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes : TOpChangeAccountInfoTypes) : String;
     //
     Function toString : String; Override;
     Property Data : TOpMultiOperationData read FData;
@@ -197,7 +197,7 @@ begin
   Result := -1;
 end;
 
-class function TOpMultiOperation.OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes: TOpChangeAccountInfoTypes): AnsiString;
+class function TOpMultiOperation.OpChangeAccountInfoTypesToText(const OpChangeAccountInfoTypes: TOpChangeAccountInfoTypes): String;
 Var opcit : TOpChangeAccountInfoType;
 begin
   Result := '';
@@ -211,7 +211,7 @@ end;
 
 procedure TOpMultiOperation.FillOperationResume(Block : Cardinal; getInfoForAllAccounts : Boolean; Affected_account_number : Cardinal; var OperationResume : TOperationResume);
 Var iSender,iReceiver,iChanger : Integer;
-  changerTxt : AnsiString;
+  changerTxt : String;
 begin
   inherited FillOperationResume(Block, getInfoForAllAccounts, Affected_account_number, OperationResume);
   OperationResume.isMultiOperation:=True;
@@ -744,7 +744,7 @@ Var i : Integer;
   _sign : TECDSA_SIG;
 begin
   Result := 0;
-  If Not Assigned(key.PrivateKey) then begin
+  If Not key.HasPrivateKey then begin
     exit;
   end;
   raw := GetDigestToSign(current_protocol);

+ 9 - 8
src/core/UWallet.pas

@@ -151,7 +151,7 @@ uses
   {$IFDEF INTERNAL_USE_FOLDERHELPER_UNIT}
   UFolderHelper,
   {$ENDIF}
-  UAES;
+  UPCEncryption;
 
 Const
   CT_PrivateKeyFile_Magic = 'TWalletKeys';
@@ -175,8 +175,9 @@ end;
 
 function TWalletKeys.AddPrivateKey(Const Name : String; ECPrivateKey: TECPrivateKey): Integer;
 Var P : PWalletKey;
-  raw_priv2hexa : TRawBytes;
+  raw_priv2hexa, LWalletPassword : TRawBytes;
 begin
+  LWalletPassword.FromString(WalletPassword);
   if Not Find(ECPrivateKey.PublicKey,Result) then begin
     // Result is new position
     New(P);
@@ -184,7 +185,7 @@ begin
     P^.Name := Name;
     P^.AccountKey := ECPrivateKey.PublicKey;
     raw_priv2hexa.FromString(TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
-    P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(raw_priv2hexa,WalletPassword);
+    P^.CryptedKey := TPCEncryption.DoPascalCoinAESEncrypt(raw_priv2hexa,LWalletPassword);
     P^.PrivateKey := TECPrivateKey.Create;
     P^.PrivateKey.SetPrivateKeyFromHexa(ECPrivateKey.EC_OpenSSL_NID, TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
     P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECPrivateKey.PublicKey);
@@ -197,7 +198,7 @@ begin
       If Not TAccountComp.EqualAccountKeys(P^.AccountKey,ECPrivateKey.PublicKey) then
         raise Exception.Create('[UWallet.pas] TWalletKeys.AddPrivateKey - consistency check failed when overriding watch-only key');
       raw_priv2hexa.FromString(TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
-      P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(raw_priv2hexa,WalletPassword);
+      P^.CryptedKey := TPCEncryption.DoPascalCoinAESEncrypt(raw_priv2hexa,LWalletPassword);
       P^.PrivateKey := TECPrivateKey.Create;
       P^.PrivateKey.SetPrivateKeyFromHexa(ECPrivateKey.EC_OpenSSL_NID, TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
     end;
@@ -315,7 +316,7 @@ begin
   for i := 0 to FSearchableKeys.Count - 1 do begin
     P := FSearchableKeys[i];
     if P^.HasPrivateKey then begin
-      isOk := TAESComp.EVP_Decrypt_AES256( P^.CryptedKey, TEncoding.ASCII.GetBytes(FWalletPassword), raw );
+      isOk := TPCEncryption.DoPascalCoinAESDecrypt(P^.CryptedKey, TEncoding.ASCII.GetBytes(FWalletPassword), raw );
       If isOk then begin
         P^.PrivateKey := TECPrivateKey.Create;
         try
@@ -453,7 +454,7 @@ begin
     P := FSearchableKeys[i];
     If Assigned(P^.PrivateKey) then begin
       raw_priv2hexa.FromString(TCrypto.PrivateKey2Hexa(P^.PrivateKey.PrivateKey));
-      P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(raw_priv2hexa,FWalletPassword);
+      P^.CryptedKey :=  TPCEncryption.DoPascalCoinAESEncrypt(raw_priv2hexa,TEncoding.ASCII.GetBytes(FWalletPassword));
     end else begin
       if FIsValidPassword then begin
         TLog.NewLog(lterror,Classname,Format('Fatal error: Private key not found %d/%d',[i+1,FSearchableKeys.Count]));
@@ -640,7 +641,7 @@ end;
 
 class function TWallet.ExportPrivateKey(const AKey: TWalletKey; const APassword: String) : String;
 begin
-  Result := TCrypto.ToHexaString(TAESComp.EVP_Encrypt_AES256(AKey.PrivateKey.ExportToRaw, TEncoding.ANSI.GetBytes(APassword)));
+  Result := TPCEncryption.DoPascalCoinAESEncrypt(AKey.PrivateKey.ExportToRaw,TEncoding.ANSI.GetBytes(APassword)).ToHexaString;
 end;
 
 class procedure TWallet.ImportPrivateKey(const AName, AKeyImportText, APassword: String);
@@ -800,7 +801,7 @@ begin
     exit;
   end;
   decrypt := Nil;
-  If (TAESComp.EVP_Decrypt_AES256(TCrypto.HexaToRaw(AKeyHexString),AKeyPassword,decrypt)) then begin
+  if TPCEncryption.DoPascalCoinAESDecrypt(TCrypto.HexaToRaw(AKeyHexString),TEncoding.ANSI.GetBytes(AKeyPassword),decrypt) then begin
     if (Length(decrypt)>0) then begin
       AKey := TECPrivateKey.ImportFromRaw(decrypt);
       Result := Assigned(AKey);

Some files were not shown because too many files changed in this diff