Browse Source

Merge pull request #45 from PascalCoinDev/master

Release 5.4.Beta5
Albert Molina 4 years ago
parent
commit
16e9976cf2
5 changed files with 177 additions and 29 deletions
  1. 17 1
      CHANGELOG.md
  2. 1 1
      src/core/UConst.pas
  3. 118 2
      src/core/UEPasaDecoder.pas
  4. 36 22
      src/core/URPC.pas
  5. 5 3
      src/gui-classic/UFRMOperation.pas

+ 17 - 1
CHANGELOG.md

@@ -1,7 +1,7 @@
 # Changelog
 
 ## Build 5.4 - (PENDING RELEASE)
-- CURRENT 5.4.Beta4
+- CURRENT 5.4.Beta5
 - Added usage of AbstractMem library to allow build a PascalCoin version using virtual memory and efficient caching mechanism
   - Use AbstractMem library v1.2
   - Must activate {$DEFINE USE_ABSTRACTMEM} at config.inc file (Enabled by default)
@@ -22,6 +22,22 @@
       - "payload_method" : (String) Can be "key" or "pwd"
       - "enc_pubkey" : HexaString with public key (if "payload_method"="key")
       - "pwd" : String with password used (if "payload_method"="pwd")
+  - New method "checkepasa": Check that "account_epasa" param contains a valid E-PASA format. Returns an "EPasa Object" (See below)
+  - New method "validateepasa": Creates an "account_epasa" with provided data and returns an "EPasa Object" (See below)
+    - "account" : Valid number or account name  ( Use @ for a PayToKey )
+    - "payload_method" : "none","dest","sender","aes"
+    - "pwd" : If "payload_method" = "aes"
+    - "payload_encode" : "string"(default) | "hexa" | "base58"
+    - "payload" : HEXASTRING with the payload data
+  - "EPasa Object" params:
+    - "account_epasa" : (String) Encoded EPASA
+    - "account" : number or name 
+    - "payload_method" : "none","dest","sender","aes"
+    - "pwd" : (String) Provided only if "payload_method" = "aes"
+    - "payload_encode" : "string"(default) | "hexa" | "base58"
+    - "account_epasa_checksum" : (String) Encoded EPASA with extended checksum
+    - "payload" : HEXASTRING with the payload data
+    - "payload_type" : Byte
   - Payload encoding will automatically set "payload_type" value based on encoding params in order to store E-PASA standard
   - Updated "findaccounts": 
     -New param "end" (integer, -1 for default): Will search from "start" to "end" (if "end"=-1 will search to the end)

+ 1 - 1
src/core/UConst.pas

@@ -198,7 +198,7 @@ Const
   CT_OpSubtype_Data_Signer                = 103;
   CT_OpSubtype_Data_Receiver              = 104;
 
-  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4.Beta4'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4.Beta4'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : String = {$IFDEF PRODUCTION}'5.4.Beta5'{$ELSE}{$IFDEF TESTNET}'TESTNET 5.4.Beta5'{$ELSE}{$ENDIF}{$ENDIF};
 
   CT_Discover_IPs = {$IFDEF PRODUCTION}'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.dynamic-dns.net;pascalcoin2.dynamic-dns.net;pascalcoin1.dns1.us;pascalcoin2.dns1.us;pascalcoin1.dns2.us;pascalcoin2.dns2.us'
                     {$ELSE}'pascaltestnet1.dynamic-dns.net;pascaltestnet2.dynamic-dns.net;pascaltestnet1.dns1.us;pascaltestnet2.dns1.us'{$ENDIF};

+ 118 - 2
src/core/UEPasaDecoder.pas

@@ -32,7 +32,8 @@ uses
   UAccounts,
   UEncoding,
   UEPasa,
-  UWallet;
+  UWallet,
+  URPC, UJSONFunctions;
 
 type
   TDecodeEPasaResult = (der_Decoded, der_Undefined, der_NonDeterministic, der_InvalidPayloadType, der_AccountNameNotFound, der_NotEnoughData, der_PrivateKeyNotFound, der_PasswordNotFound);
@@ -44,11 +45,14 @@ type
     class Function TryDecodeEPASA(AAccount : Cardinal; const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>;
       out AEPasa : TEPasa) : Boolean; overload;
     class Function DecodeEPASA(AAccount : Cardinal; const APayload : TOperationPayload; const ANode : TNode; const AWalletKeys : TWalletKeys; const APasswords : TList<String>) : String; overload;
+    class function CheckEPasa(const ASender : TRPCProcess; const AAccount_EPasa : String; AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean; overload;
+    class function CheckEPasa(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean; overload;
+    class function ValidateEPasa(const ASender : TRPCProcess; const AMethodName : String; AInputParams, AJSONResponse : TPCJSONObject; var AErrorNum : Integer; var AErrorDesc : String) : Boolean;
   End;
 
 implementation
 
-uses UPCEncryption, UCommon;
+uses UPCEncryption, UCommon, UCrypto;
 
 { TEPasaDecoder }
 
@@ -158,6 +162,58 @@ begin
   Result := true;
 end;
 
+class function TEPasaDecoder.CheckEPasa(const ASender: TRPCProcess;
+  const AMethodName: String; AInputParams, AJSONResponse: TPCJSONObject;
+  var AErrorNum: Integer; var AErrorDesc: String): Boolean;
+begin
+  Result := CheckEPAsa(ASender,AInputParams.AsString('account_epasa',''),AJSONResponse,AErrorNum,AErrorDesc);
+end;
+
+class function TEPasaDecoder.CheckEPasa(const ASender: TRPCProcess;
+  const AAccount_EPasa: String; AJSONResponse: TPCJSONObject;
+  var AErrorNum: Integer; var AErrorDesc: String): Boolean;
+var LEPasa : TEPasa;
+begin
+  if Not TEPasa.TryParse(AAccount_EPasa,LEPasa) then begin
+    AErrorNum := CT_RPC_ErrNum_InvalidEPASA;
+    AErrorDesc := 'Not a valid epasa: '+AAccount_EPasa;
+    Result := False;
+    Exit(False);
+  end else begin
+    Result := True;
+    AJSONResponse.GetAsVariant('account_epasa').Value := LEPasa.ToClassicPASAString;
+    AJSONResponse.GetAsVariant('account_epasa_checksum').Value := LEPasa.ToString(False);
+
+    if LEPasa.PayloadType.HasTrait(ptAddressedByName) then begin
+      AJSONResponse.GetAsVariant('account').Value := LEPasa.AccountName;
+    end else begin
+      AJSONResponse.GetAsVariant('account').Value := LEPasa.Account.Value;
+    end;
+
+    if LEPasa.PayloadType.HasTrait(ptPublic) then begin
+      AJSONResponse.GetAsVariant('payload_method').Value := 'none';
+    end else if LEPasa.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
+      AJSONResponse.GetAsVariant('payload_method').Value := 'sender';
+    end else if LEPasa.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
+      AJSONResponse.GetAsVariant('payload_method').Value := 'dest';
+    end else if LEPasa.PayloadType.HasTrait(ptPasswordEncrypted) then begin
+      AJSONResponse.GetAsVariant('payload_method').Value := 'aes';
+      AJSONResponse.GetAsVariant('pwd').Value := LEPasa.Password;
+    end;
+
+    if LEPasa.PayloadType.HasTrait(ptAsciiFormatted) then begin
+      AJSONResponse.GetAsVariant('payload_encode').Value := 'string';
+    end else if LEPasa.PayloadType.HasTrait(ptHexFormatted) then begin
+      AJSONResponse.GetAsVariant('payload_encode').Value := 'hexa';
+    end else if LEPasa.PayloadType.HasTrait(ptBase58Formatted) then begin
+      AJSONResponse.GetAsVariant('payload_encode').Value := 'base58';
+    end;
+
+    AJSONResponse.GetAsVariant('payload').Value := LEPasa.GetRawPayloadBytes.ToHexaString;
+    AJSONResponse.GetAsVariant('payload_type').Value := LEPasa.PayloadType.ToProtocolValue;
+  end;
+end;
+
 class function TEPasaDecoder.DecodeEPASA(AAccount: Cardinal;
   const APayload: TOperationPayload; const ANode: TNode;
   const AWalletKeys: TWalletKeys; const APasswords: TList<String>): String;
@@ -176,4 +232,64 @@ begin
   Result := TryDecodeEPASA(AAccount,APayload,ANode,AWalletKeys,APasswords,LDecodeEPasaResult,AEPasa);
 end;
 
+class function TEPasaDecoder.ValidateEPasa(const ASender: TRPCProcess;
+  const AMethodName: String; AInputParams, AJSONResponse: TPCJSONObject;
+  var AErrorNum: Integer; var AErrorDesc: String): Boolean;
+var
+  s : String;
+  card : Cardinal;
+  LEPasaStr, LDelimStart,LDelimEnd, LPwdZone, LPayload : String;
+  LRawPayload : TRawBytes;
+begin
+  LEPasaStr := '';
+  LPwdZone := '';
+  LEPasaStr := AInputParams.AsString('account','');
+  s := Trim(AInputParams.AsString('payload_method','none'));
+  if s='dest' then begin
+    LDelimStart := '(';
+    LDelimEnd := ')';
+  end else if s='sender' then begin
+    LDelimStart := '<';
+    LDelimEnd := '>';
+  end else if s='aes' then begin
+    LDelimStart := '{';
+    LDelimEnd := '}';
+    LPwdZone := ':' + AInputParams.AsString('pwd','');
+  end else if (s='none') or (trim(s)='') then begin
+    LDelimStart := '[';
+    LDelimEnd := ']';
+  end else begin
+    AErrorNum := CT_RPC_ErrNum_InvalidData;
+    AErrorDesc := Format('"payload_method" %s not valid',[s]);
+    Exit(False);
+  end;
+  s := Trim(AInputParams.AsString('payload',''));
+  if Not TCrypto.HexaToRaw(s,LRawPayload) then begin
+    AErrorNum := CT_RPC_ErrNum_InvalidData;
+    AErrorDesc := Format('"payload" is not an HEXASTRING: %s',[s]);
+    Exit(False);
+  end;
+  s := Trim(AInputParams.AsString('payload_encode','string'));
+  if s='hexa' then begin
+    LPayload := '0x'+LRawPayload.ToHexaString;
+  end else if s='base58' then begin
+    LPayload := TPascalBase58Encoding.Encode(LRawPayload);
+  end else if (s='string') or (Trim(s)='') then begin
+    LPayload := '"'+TPascalAsciiEncoding.Escape(LRawPayload.ToString)+'"';
+  end else begin
+    AErrorNum := CT_RPC_ErrNum_InvalidData;
+    AErrorDesc := Format('"payload_encode" %s not valid',[s]);
+    Exit(False);
+  end;
+
+  LEPasaStr := AInputParams.AsString('account','') + LDelimStart + LPayload + LPwdZone + LDelimEnd;
+  Result := CheckEPasa(ASender,LEPasaStr,AJSONResponse,AErrorNum,AErrorDesc);
+end;
+
+initialization
+  TRPCProcess.RegisterProcessMethod('validateepasa',TEPasaDecoder.ValidateEPasa);
+  TRPCProcess.RegisterProcessMethod('checkepasa',TEPasaDecoder.CheckEPasa);
+finalization
+  TRPCProcess.UnregisterProcessMethod('validateepasa');
+  TRPCProcess.UnregisterProcessMethod('checkepasa');
 end.

+ 36 - 22
src/core/URPC.pas

@@ -471,27 +471,41 @@ Begin
 end;
 
 class function TPascalCoinJSONComp.OverridePayloadParams(const AInputParams : TPCJSONObject; const AEPASA : TEPasa) : Boolean;
+var LPayloadmethod_old,LPayloadmethod_new : String;
+    LPayload_old, LPayload_new : String;
+    LPwd_old, LPwd_new : String;
 begin
-   // none, dest, sender, aes, payload, pwd
-   if (NOT AEPASA.IsClassicPASA) AND (AInputParams.HasValue('payload') OR AInputParams.HasValue('payload_method') OR AInputParams.HasValue('pwd')) then
-     Exit(False);
-
-   if AEPASA.PayloadType.HasTrait(ptPublic) then begin
-     AInputParams.GetAsVariant('payload_method').Value := 'none';
-     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
-   end else if AEPASA.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
-     AInputParams.GetAsVariant('payload_method').Value := 'sender';
-     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
-   end else if AEPASA.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
-     AInputParams.GetAsVariant('payload_method').Value := 'dest';
-     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
-   end else if AEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then begin
-     AInputParams.GetAsVariant('payload_method').Value := 'aes';
-     AInputParams.GetAsVariant('payload').Value := AEPASA.GetRawPayloadBytes.ToHexaString;
-     AInputParams.GetAsVariant('pwd').Value := AEPASA.Password;
-     Result := True;
-   end;
-   Result := True;
+  if AEPASA.IsClassicPASA then Exit(True);   // Not an EPASA
+
+  if AInputParams.HasValue('payload') then LPayload_old := AInputParams.AsString('payload','')
+  else LPayload_old := '';
+  if AInputParams.HasValue('payload_method') then LPayloadmethod_old := AInputParams.AsString('payload_method','')
+  else LPayloadmethod_old := '';
+  if AInputParams.HasValue('pwd') then LPwd_old := AInputParams.AsString('pwd','')
+  else LPwd_old := '';
+
+  if AEPASA.PayloadType.HasTrait(ptPublic) then begin
+    LPayloadmethod_new := 'none';
+  end else if AEPASA.PayloadType.HasTrait(ptSenderKeyEncrypted) then begin
+    LPayloadmethod_new := 'sender';
+  end else if AEPASA.PayloadType.HasTrait(ptRecipientKeyEncrypted) then begin
+    LPayloadmethod_new := 'dest';
+  end else if AEPASA.PayloadType.HasTrait(ptPasswordEncrypted) then begin
+    LPayloadmethod_new := 'aes';
+  end;
+  LPayload_new := AEPASA.GetRawPayloadBytes.ToHexaString;
+  LPwd_new := AEPASA.Password;
+
+  if (LPayloadmethod_old<>'') and (LPayloadmethod_old<>LPayloadmethod_new) then Exit(False);
+  AInputParams.GetAsVariant('payload_method').Value := LPayloadmethod_new;
+
+  if (LPayload_old<>'') and (LPayload_old<>LPayload_new) then Exit(False);
+  AInputParams.GetAsVariant('payload').Value := LPayload_new;
+
+  if (LPwd_old<>'') and (LPwd_old<>LPwd_new) then Exit(False);
+  if (LPwd_new<>'') then AInputParams.GetAsVariant('pwd').Value := LPwd_new;
+
+  Result := True;
 end;
 
 class function TPascalCoinJSONComp.CapturePubKey(
@@ -2553,8 +2567,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           Exit(False);
         end;
         // Override the JSON args (processed later by caller)
-        AJSONObj.SetAs('payload', TPCJSONVariantValue.CreateFromVariant(LEPasa.GetRawPayloadBytes.ToHexaString));
-        AJSONObj.SetAs('payload_type', TPCJSONVariantValue.CreateFromVariant(LEPasa.PayloadType.ToProtocolValue));
+        AJSONObj.GetAsVariant('payload').Value := LEPasa.GetRawPayloadBytes.ToHexaString;
+        AJSONObj.GetAsVariant('payload_type').Value := LEPasa.PayloadType.ToProtocolValue;
       end;
       AAccount := LEPasa.Account.Value;
       Result := True;

+ 5 - 3
src/gui-classic/UFRMOperation.pas

@@ -1663,9 +1663,11 @@ begin
   try
     LTargetEPASA := TEPasa.Empty;
 
-    if NOT TEPasa.TryParse(ebDestAccount.Text, LTargetEPASA) then begin
-      AErrors := 'Indeterminable target';
-      Exit(False);
+    If (PageControlOpType.ActivePage=tsTransaction) then begin
+      if NOT TEPasa.TryParse(ebDestAccount.Text, LTargetEPASA) then begin
+        AErrors := 'Indeterminable target';
+        Exit(False);
+      end;
     end;
 
     if (LUserPayloadString='') then begin