public void AccountName_Short_WithChecksum() { var parser = NewInstance(); var epasaText = "a"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); }
public void PayToKey_WithChecksum() { var parser = NewInstance(); var epasaText = "@[1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2]"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.IsTrue(epasa.IsPayToKey); }
public void AccountNumber_0_10() { var parser = NewInstance(); Assert.IsTrue(parser.TryParse("0-10", out var epasa)); Assert.AreEqual(0, epasa.Account); Assert.AreEqual(10, epasa.AccountChecksum); Assert.AreEqual(EPasaHelper.ComputeExtendedChecksum("0-10"), epasa.ExtendedChecksum); Assert.AreEqual(PayloadType.NonDeterministic, epasa.PayloadType); Assert.AreEqual($"0-10:{EPasaHelper.ComputeExtendedChecksum("0-10")}", epasa.ToString()); }
public void AccountNumber_ExtendedChecksum() { var parser = NewInstance(); var epasaText = "77-44"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.AreEqual(77, epasa.Account); Assert.AreEqual(44, epasa.AccountChecksum); Assert.AreEqual(checksum, epasa.ExtendedChecksum); Assert.AreEqual(PayloadType.NonDeterministic, epasa.PayloadType); Assert.AreEqual(epasaText, epasa.ToString()); }
public void AccountName() { var parser = NewInstance(); var epasaText = "pascalcoin-foundation"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.AreEqual(null, epasa.Account); Assert.AreEqual(null, epasa.AccountChecksum); Assert.AreEqual("pascalcoin-foundation", epasa.AccountName); Assert.AreEqual(checksum, epasa.ExtendedChecksum); Assert.AreEqual(PayloadType.NonDeterministic | PayloadType.AddressedByName, epasa.PayloadType); Assert.AreEqual($"{epasaText}:{checksum}", epasa.ToString()); }
public void AccountNumber_Payload_ExtendedChecksum() { var parser = NewInstance(); var epasaText = @"77-44[""Hello World!""]"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.AreEqual(77, epasa.Account); Assert.AreEqual(44, epasa.AccountChecksum); Assert.AreEqual(checksum, epasa.ExtendedChecksum); Assert.AreEqual(PayloadType.Public | PayloadType.AsciiFormatted, epasa.PayloadType); Assert.AreEqual("Hello World!", epasa.Payload); Assert.AreEqual(epasaText, epasa.ToString()); }
public void AccountName_Payload_ExtendedChecksum() { var parser = NewInstance(); var epasaText = @"pascalcoin-foundation[""Hello World!""]"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.AreEqual(null, epasa.Account); Assert.AreEqual(null, epasa.AccountChecksum); Assert.AreEqual("pascalcoin-foundation", epasa.AccountName); Assert.AreEqual(checksum, epasa.ExtendedChecksum); Assert.AreEqual(PayloadType.Public | PayloadType.AsciiFormatted | PayloadType.AddressedByName, epasa.PayloadType); Assert.AreEqual("Hello World!", epasa.Payload); Assert.AreEqual(epasaText, epasa.ToString()); }
public void EdgeCase_AllEscapeChars() { var parser = NewInstance(); var name = @"(a)b{c}d[e]f:g""h<i>"; var content = @"""a(b)c:d<e>f[g\h]i{j}"; var password = name; var epasaText = $@"{Pascal64Encoding.Escape(name)}{{""{PascalAsciiEncoding.Escape(content)}"":{PascalAsciiEncoding.Escape(password)}}}"; var checksum = EPasaHelper.ComputeExtendedChecksum(epasaText); epasaText = $"{epasaText}:{checksum}"; Assert.IsTrue(parser.TryParse(epasaText, out var epasa)); Assert.AreEqual(null, epasa.Account); Assert.AreEqual(null, epasa.AccountChecksum); Assert.AreEqual(name, epasa.AccountName); Assert.AreEqual(checksum, epasa.ExtendedChecksum); Assert.AreEqual(password, epasa.Password); Assert.AreEqual(PayloadType.AddressedByName | PayloadType.PasswordEncrypted | PayloadType.AsciiFormatted, epasa.PayloadType); Assert.AreEqual(content, epasa.Payload); Assert.AreEqual(epasaText, epasa.ToString()); }
public override bool TryParse(string epasaText, out EPasa epasa, out EPasaErrorCode errorCode) { errorCode = EPasaErrorCode.Success; epasa = new EPasa(); if (string.IsNullOrEmpty(epasaText)) { errorCode = EPasaErrorCode.BadFormat; return(false); } var match = _epasaRegex.Match(epasaText); var checksumDelim = match.Groups["ChecksumDelim"].Success ? match.Groups["ChecksumDelim"].Value : null; var accountNumber = match.Groups["AccountNumber"].Success ? match.Groups["AccountNumber"].Value : null; var accountChecksum = match.Groups["Checksum"].Success ? match.Groups["Checksum"].Value : null; var accountName = match.Groups["AccountName"].Success ? match.Groups["AccountName"].Value : null; var payloadStartChar = match.Groups["PayloadStartChar"].Success ? match.Groups["PayloadStartChar"].Value : null; var payloadEndChar = match.Groups["PayloadEndChar"].Success ? match.Groups["PayloadEndChar"].Value : null; var payloadContent = match.Groups["PayloadContent"].Success ? match.Groups["PayloadContent"].Value : null; var payloadPasswordDelim = match.Groups["PayloadPasswordDelim"].Success ? match.Groups["PayloadPasswordDelim"].Value : null; var payloadPassword = match.Groups["PayloadPassword"].Success ? match.Groups["PayloadPassword"].Value : null; var extendedChecksumDelim = match.Groups["ExtendedChecksumDelim"].Success ? match.Groups["ExtendedChecksumDelim"].Value : null; var extendedChecksum = match.Groups["ExtendedChecksum"].Success ? match.Groups["ExtendedChecksum"].Value : null; // Check parsed completely if (epasaText != match.Value) { errorCode = EPasaErrorCode.BadFormat; return(false); } if (accountName != null) { // Account Name if (string.IsNullOrEmpty(accountName)) { errorCode = EPasaErrorCode.BadFormat; return(false); } epasa.PayloadType = epasa.PayloadType | PayloadType.AddressedByName; epasa.AccountName = Pascal64Encoding.Unescape(accountName); epasa.Account = epasa.AccountChecksum = null; } else { // Account Number if (!uint.TryParse(accountNumber, out var accNo)) { errorCode = EPasaErrorCode.InvalidAccountNumber; return(false); } epasa.Account = accNo; var actualAccountChecksum = AccountHelper.CalculateAccountChecksum(accNo); if (checksumDelim != null) { // validate account checksum if (!uint.TryParse(accountChecksum, out var accChecksum)) { errorCode = EPasaErrorCode.AccountChecksumInvalid; return(false); } if (accChecksum != actualAccountChecksum) { errorCode = EPasaErrorCode.BadChecksum; return(false); } } epasa.AccountChecksum = actualAccountChecksum; } // Encryption type switch (payloadStartChar) { case null: break; case "[": if (payloadEndChar != "]") { errorCode = EPasaErrorCode.MismatchedPayloadEncoding; return(false); } epasa.PayloadType = epasa.PayloadType | PayloadType.Public; break; case "(": if (payloadEndChar != ")") { errorCode = EPasaErrorCode.MismatchedPayloadEncoding; return(false); } epasa.PayloadType = epasa.PayloadType | PayloadType.RecipientKeyEncrypted; break; case "<": if (payloadEndChar != ">") { errorCode = EPasaErrorCode.MismatchedPayloadEncoding; return(false); } epasa.PayloadType = epasa.PayloadType | PayloadType.SenderKeyEncrypted; break; case "{": if (payloadEndChar != "}") { errorCode = EPasaErrorCode.MismatchedPayloadEncoding; return(false); } epasa.PayloadType = epasa.PayloadType | PayloadType.PasswordEncrypted; break; default: throw new NotSupportedException($"Unrecognized start character '{payloadStartChar}'"); } // Password if (epasa.PayloadType.HasFlag(PayloadType.PasswordEncrypted)) { if (payloadPasswordDelim == null) { errorCode = EPasaErrorCode.MissingPassword; return(false); } epasa.Password = PascalAsciiEncoding.Unescape(payloadPassword ?? ""); } else if (payloadPasswordDelim != null) { errorCode = EPasaErrorCode.UnusedPassword; return(false); } // Payload if (payloadStartChar != null) { if (payloadContent == null) { epasa.Payload = string.Empty; } else if (payloadContent.StartsWith("\"")) { epasa.PayloadType = epasa.PayloadType | PayloadType.AsciiFormatted; epasa.Payload = PascalAsciiEncoding.Unescape(payloadContent.Trim('"')); } else if (payloadContent.StartsWith("0x")) { epasa.PayloadType = epasa.PayloadType | PayloadType.HexFormatted; epasa.Payload = payloadContent.Substring(2); } else { epasa.PayloadType = epasa.PayloadType | PayloadType.Base58Formatted; epasa.Payload = payloadContent; } } // Payload Lengths if (!EPasaHelper.IsValidPayloadLength(epasa.PayloadType, epasa.Payload)) { errorCode = EPasaErrorCode.PayloadTooLarge; return(false); } // Extended Checksum var actualChecksum = EPasaHelper.ComputeExtendedChecksum(epasa.ToString(true)); if (extendedChecksumDelim != null) { if (extendedChecksum != actualChecksum) { errorCode = EPasaErrorCode.BadExtendedChecksum; return(false); } } epasa.ExtendedChecksum = actualChecksum; return(true); }
private EPasaErrorCode TryCompile(EPasaNode epasaNode, EPasa epasa) { EPasaErrorCode TryCompileAccount(AccountNode accountNode) { switch (accountNode.Type) { case TokenType.AccountName: if (!Pascal64Encoding.IsValidEscaped(accountNode.Name.Value)) { return(EPasaErrorCode.InvalidAccountName); } epasa.AccountName = Pascal64Encoding.Unescape(accountNode.Name.Value); epasa.PayloadType = epasa.PayloadType.SetFlags(PayloadType.AddressedByName); break; case TokenType.AccountNumber: if (!uint.TryParse(accountNode.AccountNo.Value, out var accNo)) { return(EPasaErrorCode.BadFormat); } if (accountNode.AccountNo.Value.StartsWith("0") && accNo != 0) { return(EPasaErrorCode.BadFormat); } epasa.Account = accNo; var actualChecksum = AccountHelper.CalculateAccountChecksum(accNo); if (accountNode.Checksum != null) { if (!uint.TryParse(accountNode.Checksum.Value, out var checksum)) { return(EPasaErrorCode.BadFormat); } if (checksum != actualChecksum) { return(EPasaErrorCode.AccountChecksumInvalid); } } epasa.AccountChecksum = actualChecksum; break; default: throw new ArgumentOutOfRangeException(nameof(accountNode)); } return(EPasaErrorCode.Success); } EPasaErrorCode TryCompilePayload(PayloadNode payloadNode) { epasa.PayloadType = epasa.PayloadType | payloadNode.Encryption; if (payloadNode.Content != null) { switch (payloadNode.Content.Type) { case TokenType.PascalAsciiString: epasa.PayloadType = epasa.PayloadType | PayloadType.AsciiFormatted; epasa.Payload = PascalAsciiEncoding.Unescape(payloadNode.Content.Value); break; case TokenType.Base58String: epasa.PayloadType = epasa.PayloadType | PayloadType.Base58Formatted; epasa.Payload = payloadNode.Content.Value; break; case TokenType.HexString: epasa.PayloadType = epasa.PayloadType | PayloadType.HexFormatted; epasa.Payload = payloadNode.Content.Value; break; default: throw new ArgumentOutOfRangeException(nameof(payloadNode.Content.Type)); } if (!EPasaHelper.IsValidPayloadLength(epasa.PayloadType, epasa.Payload)) { return(EPasaErrorCode.PayloadTooLarge); } } if (payloadNode.Password != null) { if (!EPasaHelper.IsValidPasswordLength(payloadNode.Password.Value)) { return(EPasaErrorCode.InvalidPassword); } epasa.Password = PascalAsciiEncoding.Unescape(payloadNode.Password.Value); } return(EPasaErrorCode.Success); } EPasaErrorCode TryCompileExtendedChecksum(ValueNode extendedChecksumNode) { var actualExtendedChecksum = EPasaHelper.ComputeExtendedChecksum(epasa.ToString(true)); if (extendedChecksumNode != null && extendedChecksumNode.Value != actualExtendedChecksum) { return(EPasaErrorCode.AccountChecksumInvalid); } epasa.ExtendedChecksum = actualExtendedChecksum; return(EPasaErrorCode.Success); } var result = TryCompileAccount(epasaNode.Account); if (result != EPasaErrorCode.Success) { return(result); } if (epasaNode.Payload != null) { result = TryCompilePayload(epasaNode.Payload); if (result != EPasaErrorCode.Success) { return(result); } } result = TryCompileExtendedChecksum(epasaNode.ExtendedChecksum); if (result != EPasaErrorCode.Success) { return(result); } return(result); }