Browse Source

EPasa: cosmetic refactoring

Herman Schoenfeld 4 years ago
parent
commit
e9ed4d67f8
2 changed files with 136 additions and 92 deletions
  1. 127 92
      src/core/UEPasa.pas
  2. 9 0
      src/libraries/sphere10/UCommon.pas

+ 127 - 92
src/core/UEPasa.pas

@@ -43,39 +43,39 @@ type
     BadExtendedChecksum
   );
 
-  { PayloadType}
-
-  PayloadType = (
-    NonDeterministic = 0,      // Payload encryption and encoding method not specified.
-    &Public = 1,               // Unencrypted, public payload.
-    RecipientKeyEncrypted = 2, // ECIES encrypted using recipient accounts public key.
-    SenderKeyEncrypted = 3,    // ECIES encrypted using sender accounts public key.
-    PasswordEncrypted = 4,     // AES encrypted using pwd param
-    AsciiFormatted = 5,        // Payload data encoded in ASCII
-    HexFormatted = 6,          // Payload data encoded in HEX
-    Base58Formatted = 7,       // Payload data encoded in Base58
-    AddressedByName = 8        // E-PASA addressed by account name (not number).
+  { TPayloadTrait }
+
+  TPayloadTrait = (
+    ptNonDeterministic = 0,      // Payload encryption and encoding method not specified.
+    ptPublic = 1,               // Unencrypted, public payload.
+    ptRecipientKeyEncrypted = 2, // ECIES encrypted using recipient accounts public key.
+    ptSenderKeyEncrypted = 3,    // ECIES encrypted using sender accounts public key.
+    ptPasswordEncrypted = 4,     // AES encrypted using pwd param
+    ptAsciiFormatted = 5,        // Payload data encoded in ASCII
+    ptHexFormatted = 6,          // Payload data encoded in HEX
+    ptBase58Formatted = 7,       // Payload data encoded in Base58
+    ptAddressedByName = 8        // E-PASA addressed by account name (not number).
   );
 
-  { PayloadTypeHelper }
+  { TPayloadTraitHelper }
 
-  PayloadTypeHelper = record helper for PayloadType
+  TPayloadTraitHelper = record helper for TPayloadTrait
   public
-    function Value: Int32;
+    function ProtocolValue: byte;
   end;
 
-  { PayloadTypes }
+  { TPayloadType }
 
-  PayloadTypes = set of PayloadType;
+  TPayloadType = set of TPayloadTrait;
 
-  { PayloadTypesHelper }
+  { TPayloadTypesHelper }
 
-  PayloadTypesHelper = record helper for PayloadTypes
+  TPayloadTypeHelper = record helper for TPayloadType
   public
-    function IsPayloadTypeInSet(APayloadType: PayloadType): Boolean; inline;
+    function HasTrait(APayloadTrait: TPayloadTrait): Boolean; inline;
+    function ProtocolValue : byte;
   end;
 
-
   { TEPasa }
 
   TEPasa = record
@@ -83,16 +83,16 @@ type
       var
         FAccount, FAccountChecksum: TNullable<UInt32>;
         FAccountName, FPayload, FPassword, FExtendedChecksum: String;
-        FPayloadTypes: PayloadTypes;
+        FPayloadType: TPayloadType;
 
       function GetAccount: TNullable<UInt32>; inline;
       procedure SetAccount(const AValue: TNullable<UInt32>); inline;
       function GetAccountChecksum: TNullable<UInt32>; inline;
       procedure SetAccountChecksum(const AValue: TNullable<UInt32>); inline;
-      function GetPayloadTypes: PayloadTypes; inline;
+      function GetPayloadType: TPayloadType; inline;
       function GetAccountName: String; inline;
       procedure SetAccountName(const AValue: String); inline;
-      procedure SetPayloadTypes(const AValue: PayloadTypes); inline;
+      procedure SetPayloadType(const AValue: TPayloadType); inline;
       function GetExtendedChecksum: String; inline;
       procedure SetExtendedChecksum(const AValue: String); inline;
       function GetPassword: String; inline;
@@ -109,7 +109,7 @@ type
       property Account: TNullable<UInt32> read GetAccount write SetAccount;
       property AccountChecksum: TNullable<UInt32> read GetAccountChecksum write SetAccountChecksum;
       property AccountName: String read GetAccountName write SetAccountName;
-      property PayloadTypes: PayloadTypes read GetPayloadTypes write SetPayloadTypes;
+      property PayloadType: TPayloadType read GetPayloadType write SetPayloadType;
       property Payload: String read GetPayload write SetPayload;
       property Password: String read GetPassword write SetPassword;
       property ExtendedChecksum: String read GetExtendedChecksum write SetExtendedChecksum;
@@ -155,9 +155,9 @@ type
       function TryParse(const AEPasaText: String; out AEPasa: TEPasa; out AErrorCode: EPasaErrorCode): Boolean; overload;
   end;
 
-  { TEPasaHelper }
+  { TEPasaComp }
 
-  TEPasaHelper = class sealed(TObject)
+  TEPasaComp = class sealed(TObject)
 
     strict private
       class function ReadUInt16AsBytesLE(AValue: UInt16): TArray<Byte>; static;
@@ -177,9 +177,11 @@ type
 
       class function ComputeExtendedChecksum(const AText: String): String; static;
       class function IsValidExtendedChecksum(const AText: String; const AChecksum: String): Boolean; static;
-      class function IsValidPayloadLength(APayloadType: PayloadTypes; const APayloadContent: String): Boolean; static;
+      class function IsValidPayloadLength(APayloadType: TPayloadType; const APayloadContent: String): Boolean; static;
       class function IsValidPasswordLength(const APasswordValue: String) : Boolean; static;
 
+      class function GetPayloadTypeProtocolByte(const APayloadType : TPayloadType) : Byte;
+      class function GetPayloadTypeFromProtocolByte(AByte : Byte) : TPayloadType;
   end;
 
 resourcestring
@@ -200,30 +202,37 @@ uses
   HlpConverters,
   UMemory;
 
-{ PayloadTypeHelper }
+{ TPayloadTraitHelper }
 
-function PayloadTypeHelper.Value: Int32;
+function TPayloadTraitHelper.ProtocolValue: Byte;
 begin
   case Self of
-    NonDeterministic: Result := $00000000;
-    &Public: Result := $00000001;
-    RecipientKeyEncrypted: Result := $00000010;
-    SenderKeyEncrypted: Result := $00000100;
-    PasswordEncrypted: Result := $00001000;
-    AsciiFormatted: Result := $00010000;
-    HexFormatted: Result := $00100000;
-    Base58Formatted: Result := $01000000;
-    AddressedByName: Result := $10000000;
+    ptNonDeterministic: Result := 0;
+    ptPublic: Result := BYTE_BIT_0;
+    ptRecipientKeyEncrypted: Result := BYTE_BIT_1;
+    ptSenderKeyEncrypted: Result := BYTE_BIT_2;
+    ptPasswordEncrypted: Result := BYTE_BIT_3;
+    ptAsciiFormatted: Result := BYTE_BIT_4;
+    ptHexFormatted: Result := BYTE_BIT_5;
+    ptBase58Formatted: Result := BYTE_BIT_6;
+    ptAddressedByName: Result := BYTE_BIT_7;
   end;
+  raise Exception.Create('Internal Error 2faed11a-1b0f-447a-87d1-2e1735ac4ca2');
 end;
 
-{ PayloadTypesHelper }
+{ TPayloadTypeHelper }
+
+function TPayloadTypeHelper.HasTrait(APayloadTrait : TPayloadTrait) : Boolean;
+begin
+  Result := APayloadTrait in Self;
+end;
 
-function PayloadTypesHelper.IsPayloadTypeInSet(APayloadType : PayloadType) : Boolean;
+function TPayloadTypeHelper.ProtocolValue : Byte;
 begin
-  Result := APayloadType in Self;
+  Result := TEPasaComp.GetPayloadTypeProtocolByte(Self);
 end;
 
+
 { TEPasa }
 
 function TEPasa.GetAccount: TNullable<UInt32>;
@@ -256,9 +265,9 @@ begin
   Result := FPayload;
 end;
 
-function TEPasa.GetPayloadTypes: PayloadTypes;
+function TEPasa.GetPayloadType: TPayloadType;
 begin
-  Result := FPayloadTypes;
+  Result := FPayloadType;
 end;
 
 procedure TEPasa.SetAccount(const AValue: TNullable<UInt32>);
@@ -291,29 +300,29 @@ begin
   FPayload := AValue;
 end;
 
-procedure TEPasa.SetPayloadTypes(const AValue: PayloadTypes);
+procedure TEPasa.SetPayloadType(const AValue: TPayloadType);
 begin
-  FPayloadTypes := AValue;
+  FPayloadType := AValue;
 end;
 
 function TEPasa.IsPayToKey: Boolean;
 begin
   Result :=
     (AccountName = '@') and
-    (PayloadTypes.IsPayloadTypeInSet(PayloadType.AddressedByName) and
-    PayloadTypes.IsPayloadTypeInSet(PayloadType.Public) and
-    PayloadTypes.IsPayloadTypeInSet(PayloadType.Base58Formatted));
+    (PayloadType.HasTrait(ptAddressedByName) and
+    PayloadType.HasTrait(ptPublic) and
+    PayloadType.HasTrait(ptBase58Formatted));
 end;
 
 function TEPasa.GetRawPayloadBytes: TArray<Byte>;
 begin
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.AsciiFormatted)) then
+  if (PayloadType.HasTrait(ptAsciiFormatted)) then
     Exit(TEncoding.ASCII.GetBytes(Payload));
 
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.Base58Formatted)) then
+  if (PayloadType.HasTrait(ptBase58Formatted)) then
     Exit(TPascalBase58Encoding.Decode(Payload));
 
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.HexFormatted)) then
+  if (PayloadType.HasTrait(ptHexFormatted)) then
     Exit(THexEncoding.Decode(Payload));
 
   raise EPascalCoinException.CreateRes(@SUnknownPayloadEncoding);
@@ -324,7 +333,7 @@ var
   LPayloadContent: String;
 begin
   Result := string.Empty;
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.AddressedByName)) then begin
+  if (PayloadType.HasTrait(ptAddressedByName)) then begin
     Result := Result + TPascal64Encoding.Escape(AccountName);
   end else begin
     Result := Result + Account.Value.ToString();
@@ -333,24 +342,24 @@ begin
     end;
   end;
 
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.AsciiFormatted)) then begin
+  if (PayloadType.HasTrait(ptAsciiFormatted)) then begin
     LPayloadContent := String.Format('"%s"', [TPascalAsciiEncoding.Escape(Payload)]);
-  end else if (PayloadTypes.IsPayloadTypeInSet(PayloadType.HexFormatted)) then begin
+  end else if (PayloadType.HasTrait(ptHexFormatted)) then begin
     LPayloadContent := string.Format('0x%s', [Payload]);
-  end else if (PayloadTypes.IsPayloadTypeInSet(PayloadType.Base58Formatted)) then begin
+  end else if (PayloadType.HasTrait(ptBase58Formatted)) then begin
     LPayloadContent := string.Format('%s', [Payload]);
   end else begin
     // it is non-deterministic, so payload content is ignored
     LPayloadContent := string.Empty;
   end;
 
-  if (PayloadTypes.IsPayloadTypeInSet(PayloadType.Public)) then begin
+  if (PayloadType.HasTrait(ptPublic)) then begin
     Result := Result + string.Format('[%s]', [LPayloadContent]);
-  end else if (PayloadTypes.IsPayloadTypeInSet(PayloadType.RecipientKeyEncrypted)) then begin
+  end else if (PayloadType.HasTrait(ptRecipientKeyEncrypted)) then begin
     Result := Result + string.Format('(%s)', [LPayloadContent]);
-  end else if (PayloadTypes.IsPayloadTypeInSet(PayloadType.SenderKeyEncrypted)) then begin
+  end else if (PayloadType.HasTrait(ptSenderKeyEncrypted)) then begin
     Result := Result + string.Format('<%s>', [LPayloadContent]);
-  end else if (PayloadTypes.IsPayloadTypeInSet(PayloadType.PasswordEncrypted)) then begin
+  end else if (PayloadType.HasTrait(ptPasswordEncrypted)) then begin
     Result := Result + string.Format('{%s:%s}', [LPayloadContent, TPascalAsciiEncoding.Escape(Password)]);
   end else begin
     // it is non-deterministic, so payload omitted entirely
@@ -465,8 +474,8 @@ begin
     // when multiple enums are OR'ed in C#, they are combined and
     // if any of the enums numeric value is zero, it is excluded.
     // in our case,"PayloadType.NonDeterministic" is always zero so we exclude it from our set.
-    AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.AddressedByName] -
-      [PayloadType.NonDeterministic];
+    AEPasa.PayloadType := AEPasa.PayloadType + [ptAddressedByName] -
+      [ptNonDeterministic];
     AEPasa.AccountName := TPascal64Encoding.Unescape(LAccountName);
     AEPasa.Account := Nil;
     AEPasa.AccountChecksum := Nil;
@@ -504,23 +513,23 @@ begin
           AErrorCode := EPasaErrorCode.MismatchedPayloadEncoding;
           Exit(False);
         end;
-        AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.Public] -
-          [PayloadType.NonDeterministic];
+        AEPasa.PayloadType := AEPasa.PayloadType + [ptPublic] -
+          [ptNonDeterministic];
       end;
      '(': begin
         if (LPayloadEndChar <> ')') then begin
           AErrorCode := EPasaErrorCode.MismatchedPayloadEncoding;
           Exit(False);
         end;
-        AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.RecipientKeyEncrypted] - [PayloadType.NonDeterministic];
+        AEPasa.PayloadType := AEPasa.PayloadType + [ptRecipientKeyEncrypted] - [ptNonDeterministic];
       end;
     '<': begin
         if (LPayloadEndChar <> '>') then begin
           AErrorCode := EPasaErrorCode.MismatchedPayloadEncoding;
           Exit(False);
         end;
-        AEPasa.PayloadTypes := AEPasa.PayloadTypes +
-          [PayloadType.SenderKeyEncrypted] - [PayloadType.NonDeterministic];
+        AEPasa.PayloadType := AEPasa.PayloadType +
+          [ptSenderKeyEncrypted] - [ptNonDeterministic];
       end;
 
     '{': begin
@@ -528,13 +537,13 @@ begin
           AErrorCode := EPasaErrorCode.MismatchedPayloadEncoding;
           Exit(False);
         end;
-        AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.PasswordEncrypted] - [PayloadType.NonDeterministic];
+        AEPasa.PayloadType := AEPasa.PayloadType + [ptPasswordEncrypted] - [ptNonDeterministic];
       end
       else raise ENotSupportedException.CreateResFmt(@SUnRecognizedStartCharacter, [LPayloadStartChar]);
   end;
 
   // Password
-  if (AEPasa.PayloadTypes.IsPayloadTypeInSet(PayloadType.PasswordEncrypted)) then begin
+  if (AEPasa.PayloadType.HasTrait(ptPasswordEncrypted)) then begin
     if (LPayloadPasswordDelim = #0) then begin
       AErrorCode := EPasaErrorCode.MissingPassword;
       Exit(False);
@@ -551,25 +560,25 @@ begin
     if (LPayloadContent = #0) then begin
       AEPasa.Payload := string.Empty;
     end else if (LPayloadContent.StartsWith('"')) then begin
-      AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.AsciiFormatted] - [PayloadType.NonDeterministic];
+      AEPasa.PayloadType := AEPasa.PayloadType + [ptAsciiFormatted] - [ptNonDeterministic];
       AEPasa.Payload := TPascalAsciiEncoding.UnEscape(LPayloadContent.Trim(['"']));
     end else if (LPayloadContent.StartsWith('0x')) then begin
-      AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.HexFormatted] - [PayloadType.NonDeterministic];
+      AEPasa.PayloadType := AEPasa.PayloadType + [ptHexFormatted] - [ptNonDeterministic];
       AEPasa.Payload := System.Copy(LPayloadContent, 3, LPayloadContent.Length - 2);
     end else begin
-      AEPasa.PayloadTypes := AEPasa.PayloadTypes + [PayloadType.Base58Formatted] - [PayloadType.NonDeterministic];
+      AEPasa.PayloadType := AEPasa.PayloadType + [ptBase58Formatted] - [ptNonDeterministic];
       AEPasa.Payload := LPayloadContent;
     end;
   end;
 
   // Payload Lengths
-  if (not TEPasaHelper.IsValidPayloadLength(AEPasa.PayloadTypes, AEPasa.Payload)) then begin
+  if (not TEPasaComp.IsValidPayloadLength(AEPasa.PayloadType, AEPasa.Payload)) then begin
     AErrorCode := EPasaErrorCode.PayloadTooLarge;
     Exit(False);
   end;
 
   // Extended Checksum
-  LActualChecksum := TEPasaHelper.ComputeExtendedChecksum(AEPasa.ToString(True));
+  LActualChecksum := TEPasaComp.ComputeExtendedChecksum(AEPasa.ToString(True));
   if (LExtendedChecksumDelim <> #0) then begin
     if (LExtendedChecksum <> LActualChecksum) then begin
       AErrorCode := EPasaErrorCode.BadExtendedChecksum;
@@ -582,16 +591,16 @@ begin
 end;
 
 
-{ TEPasaHelper }
+{ TEPasaComp }
 
-class function TEPasaHelper.ReadUInt16AsBytesLE(AValue: UInt16): TArray<Byte>;
+class function TEPasaComp.ReadUInt16AsBytesLE(AValue: UInt16): TArray<Byte>;
 begin
   System.SetLength(Result, System.SizeOf(UInt16));
   Result[0] := Byte(AValue);
   Result[1] := Byte(AValue shr 8);
 end;
 
-class function TEPasaHelper.ComputeExtendedChecksum(const AText: String): String;
+class function TEPasaComp.ComputeExtendedChecksum(const AText: String): String;
 var
   LHashInstance: IHashWithKey;
   LChecksum: UInt16;
@@ -602,53 +611,53 @@ begin
   Result := THexEncoding.Encode(ReadUInt16AsBytesLE(LChecksum), True);
 end;
 
-class function TEPasaHelper.IsValidExtendedChecksum(const AText, AChecksum: String): Boolean;
+class function TEPasaComp.IsValidExtendedChecksum(const AText, AChecksum: String): Boolean;
 begin
   Result := ComputeExtendedChecksum(AText) = AChecksum;
 end;
 
-class function TEPasaHelper.IsValidPayloadLength(APayloadType: PayloadTypes; const APayloadContent: String): Boolean;
+class function TEPasaComp.IsValidPayloadLength(APayloadType: TPayloadType; const APayloadContent: String): Boolean;
 begin
   if (string.IsNullOrEmpty(APayloadContent)) then
     Exit(True);
 
-  if (APayloadType.IsPayloadTypeInSet(PayloadType.Public)) then begin
+  if (APayloadType.HasTrait(ptPublic)) then begin
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.AsciiFormatted)) then
+    if (APayloadType.HasTrait(ptAsciiFormatted)) then
       Exit(TPascalAsciiEncoding.UnEscape(APayloadContent).Length <= MaxPublicAsciiContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.HexFormatted)) then
+    if (APayloadType.HasTrait(ptHexFormatted)) then
       Exit(APayloadContent.Length <= MaxPublicHexContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.Base58Formatted)) then
+    if (APayloadType.HasTrait(ptBase58Formatted)) then
       Exit(APayloadContent.Length <= MaxPublicBase58ContentLength);
 
     // unknown encoding format
     Result := False;
   end;
 
-  if (APayloadType.IsPayloadTypeInSet(PayloadType.SenderKeyEncrypted) or APayloadType.IsPayloadTypeInSet(PayloadType.RecipientKeyEncrypted)) then begin
+  if (APayloadType.HasTrait(ptSenderKeyEncrypted) or APayloadType.HasTrait(ptRecipientKeyEncrypted)) then begin
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.AsciiFormatted)) then
+    if (APayloadType.HasTrait(ptAsciiFormatted)) then
       Exit(TPascalAsciiEncoding.UnEscape(APayloadContent).Length <= MaxECIESAsciiContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.HexFormatted)) then
+    if (APayloadType.HasTrait(ptHexFormatted)) then
       Exit(APayloadContent.Length <= MaxECIESHexContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.Base58Formatted)) then
+    if (APayloadType.HasTrait(ptBase58Formatted)) then
       Exit(APayloadContent.Length <= MaxECIESBase58ContentLength);
     // unknown encoding format
     Result := False;
   end;
 
-  if (APayloadType.IsPayloadTypeInSet(PayloadType.PasswordEncrypted)) then begin
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.AsciiFormatted)) then
+  if (APayloadType.HasTrait(ptPasswordEncrypted)) then begin
+    if (APayloadType.HasTrait(ptAsciiFormatted)) then
       Exit(TPascalAsciiEncoding.UnEscape(APayloadContent).Length <= MaxAESAsciiContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.HexFormatted)) then
+    if (APayloadType.HasTrait(ptHexFormatted)) then
       Exit(APayloadContent.Length <= MaxAESHexContentLength);
 
-    if (APayloadType.IsPayloadTypeInSet(PayloadType.Base58Formatted)) then
+    if (APayloadType.HasTrait(ptBase58Formatted)) then
       Exit(APayloadContent.Length <= MaxAESBase58ContentLength);
 
     // unknown encoding format
@@ -659,10 +668,36 @@ begin
   Result := False;
 end;
 
-class function TEPasaHelper.IsValidPasswordLength(const APasswordValue : String): Boolean;
+class function TEPasaComp.IsValidPasswordLength(const APasswordValue : String): Boolean;
 begin
   // no password length policy established (only client-side concern)
   Result := True;
 end;
 
+class function TEPasaComp.GetPayloadTypeProtocolByte(const APayloadType : TPayloadType) : Byte;
+var
+ LPayloadType : TPayloadTrait;
+begin
+  Result := 0; // NonDeterministic by default
+  for LPayloadType := Low(TPayloadTrait) to High(TPayloadTrait) do
+    if APayloadType.HasTrait(LPayloadType) then
+      Result := Result OR LPayloadType.ProtocolValue;
+end;
+
+class function TEPasaComp.GetPayloadTypeFromProtocolByte(AByte: Byte) : TPayloadType;
+var
+ LPayloadType : TPayloadTrait;
+ LPayloadTypeByte : byte;
+begin
+  if AByte = 0 then
+    Exit([ptNonDeterministic]);
+
+  Result := [];
+  for LPayloadType := Low(TPayloadTrait) to High(TPayloadTrait) do begin
+    LPayloadTypeByte := LPayloadType.ProtocolValue;
+    if (AByte AND LPayloadTypeByte) = LPayloadTypeByte then
+      Result := Result + [LPayloadType];
+  end;
+end;
+
 end.

+ 9 - 0
src/libraries/sphere10/UCommon.pas

@@ -43,6 +43,15 @@ const
   MaxSeconds = MaxMilliseconds div 60;
   MinSeconds = MinMilliseconds div 60;
 
+  BYTE_BIT_0 = byte(1);
+  BYTE_BIT_1 = byte(2);
+  BYTE_BIT_2 = byte(4);
+  BYTE_BIT_3 = byte(8);
+  BYTE_BIT_4 = byte(16);
+  BYTE_BIT_5 = byte(32);
+  BYTE_BIT_6 = byte(64);
+  BYTE_BIT_7 = byte(128);
+
 { GLOBAL HELPER FUNCTIONS }