Skip to content

Commit

Permalink
fix(tlv_conversion): Convert to Characters Rather than Hex
Browse files Browse the repository at this point in the history
The original implementation was converting to hex, whereas all we needed to do was to convert to characters and ensure ASCII-8BIT encoding.

ZATCA expects ASCII, the original implementation was assuming they were expecting hexadecimal versions of numbers, but the desired values are in ASCII.

This change ensures that the whole thing is forced to be ASCII-8BIT.

It was unclear from ZATCA if the `value` should be left as Unicode or not, but this presents a challenge because we would have to concatenate an ASCII string with a UTF-8 string and that's not possible.

We use `String.force_encoding` to ASCII-8BIT to get around those errors and avoid `String#encode` because it will throw an exception because you can't convert UTF-8 to ASCII-8BIT because there is no point of reference for what each character maps to.

This approach generates the same output as [ZATCA's SDK](https://zatca.gov.sa/en/E-Invoicing/SystemsDevelopers/ComplianceEnablementToolbox/Pages/DownloadSDK.aspx) does.
  • Loading branch information
obahareth committed Nov 12, 2021
1 parent 769eaf1 commit 09c0cf3
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 6 deletions.
9 changes: 6 additions & 3 deletions lib/zatca/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ def to_h

def to_tlv
# TLV should be concatenated together without any separator in the following
# format: hex_value_of_id hex_value_of_length value_itself
# where hex_values should be padded with a 0 if containing only a single digit.
# format: character_value_of_id character_value_of_value_length value_itself
# All of this should be in 8-bit ASCII.
tlv = @id.chr + @value.length.chr + value

sprintf("%02X%02X%s", @id, @value.length, @value)
# We need to use force_encoding because encode will raise errors when
# trying to encode a string with utf-8 characters.
tlv.force_encoding("ASCII-8BIT")
end
end
end
2 changes: 1 addition & 1 deletion spec/lib/zatca/qr_code_generator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe "#render" do
it "returns a base64 data_url" do
expect(generator.render).to eq("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQAAAAB0CZXLAAAEG0lEQVR4nO1Z3WrlIBA2q5BnCigKPlVACAEhTyUoCj5TQMl+k7PsbfeiDHtRz+lpawUn43w/Y389X4xf4ovxs+BnwX+4YC7L4qZRxWC4JvCaDi+aZgvSPmMqeR/1qjVvZl8okEbT37bFlwvm4uST1qR0K8YjkCFPn2maLwYac73XPPejpjBDE3rb3Xdv8S8LZuj1XNRcT4MAZGaNQT55OtGfqIW2o21+NPGZ5ouhLEqIbTc7YDGdFhu+xHTvNFMMErqSm5CxySvK3N+P3N5pvnqYyzp6Fnh6UdTc/elEk0mJ9n1bfLFgqv7c67343LSt9bky/WEDTAJbDEDA9EnJ5MFJWyi70zJrwAR0yXYWW5BnsEOL4nAEro9+7q7ZBJ5ii6HnElCRrRwRlfGmoEebFKWBLQ+GmNlpm6gAbC6e4lghHmwxTH8lqBSKAB9iU8IOysT9YWumPLTtqFmeZgEobU2umDW+QAVe2fgBchlwBlSWDVXp4/SxrJmzHrS2VxTET73exqyDkqAhIJz+wZUwsfeTPxs3CQdRhyjGsXEUhILSoMtunC7rDUNXQivunWXCxfFgW5jI48rYOJFy+rTjfWS+PAiJarT1DM1GEgndgFChO18exEsRlcRSIxlZEF9Dv+TLEExnEURPe0AgkG891yuiMGUGbXPmAc0FeCFr3U/V8BuKcoI5X0/JhU1l6bndhEqBp2wdJaA+xsaHTYrC6elkvY+BSKjXKg5znY+jiJEywcLhG6wkQcNG/cfcs+WhUBkAEVMVtQXdNGkI2i62GKbxlToMhIHW5oGE1vw2GJAxvh4HOAxNDtiWsaHPAj3cHgaG008WgzbTJzQ4y1ozKlHPD1HznYWssRjAUl7Pk5YdXFGCkNcZGL09tgI/WXINxT9XzRZtF7x2ZMwDttrgqNdTzQPNlQYcJHUafmi2GGRG4lERx42mIqMoX++AjofsJBtXh81HAiIAYhREwyAKRZjNnLp5oyjBU7pnC0tNvACnbyHnfF5uczb3dMSyU3tDamEHvDVfPaACgQFqtiaYiWy+jLoY6oD5YsCD+xOAKI4UorWGqrQXOIvRP2jAQT5jBjIR9oGCE3euSIZjq0k1F7epfqGlAE07WCpQd71DY+SHBHMPQpp0A3T6E9o9w9zVx0AwnQUMvUctouPVG1ouOpH+RBwHHz/gAGRagryRB+r7G2lVCXYw8sPngr7njlw4HMimgE0ZURiM/EAX9BLtnn7pGp0OmuC/l8VcevFe0Lf3Nq4ouiImQwtn6fhiEESV6L2xf7TwcPCTKE7BigsaQAbcw0L/vwFBkHiPj7vn0ovn7XMt3k9NdFEOIdeChJTP0y5KFDgYGEtw5HOaPbSe/JX59OK9oLe0oaYBmNRKB0E/s9bDz4KfBd+z4Df7L5f/KTGuaQAAAABJRU5ErkJggg==")
expect(generator.render).to eq("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQAAAAB0CZXLAAADoElEQVR4nO1Y0arsKBA0VyHfJBgU/KpAYAgI+SpBUfCbAkq22nPu687LbLMPExgmCQ12uqu6Sv88b64/4s31DfgGfAP+vwFjWZZtw8+NxeXN4VUdeF4cY5L26aKVVPP6JBvyosRQ8yVjDvh8MZyxpYu8vJ4nKpvmS8YccMnSaz6EMKYOKoNMH1/ifYAZvqS8qaqVfj3d/AdL/GuAfNLYlDAV0OjVVCDS0UvOHAiFwuhtPwgWuCN4zJdsOUgIbMJ/Sy3JJK8SCB+/L/l4sTl5JXy+yGpsmw8t4IZ1PghLn15b6ShEAEXQDzxPbnDNSR+BQe1MVljcEDM7ePK6HV8OAGDrtSXgsdrT32qgD2sCPhhzEFWvEQPKBq1s9GDqWtAUwgcbL4JpVPcW8OlDYVwntMJ9com3AeMQ2vcqCYqowJOyj4vvNLL46pAAhnZjTgviwzgMxiXqwMkLUe2t8NVjP4ZPWpF7WDsmtmPMwRA7gUkQBIWQySbwZNaEcT5cp0M7sKY8FbBBd2YcrHg4N/90IBPt8PeKOSGjarBUiS+HcWDNCorackWgocXl+K0CIy+M7ajGMRyMTEcxUnvOfZvulg0P57K8umk0mqCaGBUQkCrD55Z4H1DJPgGUNTsUREgMzYobTl5AJSFXRsNGYSa0CEg6zOrB6aOGMhI6QQYCPgrKBReV/hprPu3OSkZP1c9Kk5M6cPOTBZt2y1KCPFcMS0OFuMo5gcGYg+x5p9VvfyXZMSuMxuRcAycmRXuuErd9vaEZefOJFNMIXh8FAOyuwlGSUraOx0kKVt2EUpZSritUkWl7I1o8oFms/kHUvOHbCY/mx0/6UH/dHCMvknwwmKCU1cbJSux5WHuhD62wt8gurxd8XQQx0YqPLvEuAJrlabOPAWn0Qe2AYprKOqOwzz3X0snKnCpv2G/XrKap48tB5B1zGuL53HT6AVQSS8JHl3gbIEt048gqow4NszJCMPTB66uHsqFij/s6X/fm8r4mG+fmjy8HmIex+ys6AV5iWjY0pg5VWT3MA7cwD4AU2Sd4KjsdJqde0Dmtj9jsw8QNykQv82CKFQ90JFvRgyDneVTHLqv+SCcjJhfQAmujHSDHDiul4awE5z5rXjJoKLabtkE+V7fP6bhzEFrVhjYkcATkWBPvrJ7ECJLO6eEkLmz4QM98GFY80JEsNaHrBWBweAHlqpV13/17JAuVeiBdUAw80l/iy+Eb8A34Bnw64B8r7y//mMcBXwAAAABJRU5ErkJggg==")
end
end
end
9 changes: 8 additions & 1 deletion spec/lib/zatca/tag_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
describe ZATCA::Tag do
let(:tag) { ZATCA::Tag.new(key: :seller_name, value: "Mrsool") }
let(:unicode_tag) { ZATCA::Tag.new(key: :seller_name, value: "مرسول") }

describe "#id" do
it "gets mapped from seller_name to 1" do
Expand Down Expand Up @@ -31,7 +32,13 @@

describe "#to_tlv" do
it "generates a valid TLV" do
expect(tag.to_tlv).to eq("0106Mrsool")
expect(tag.to_tlv).to eq("\x01\x06Mrsool")
end

it "generates a valid TLV when passed unicode input" do
expected_output = "\x01\x05\xD9\x85\xD8\xB1\xD8\xB3\xD9\x88\xD9\x84".force_encoding("ASCII-8BIT")

expect(unicode_tag.to_tlv).to eq(expected_output)
end
end
end
2 changes: 1 addition & 1 deletion spec/lib/zatca/tags_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe "#to_base64" do
it "generates valid Base64" do
expect(tags.to_base64).to eq("MDEwNk1yc29vbDAyMEYzMTAyMjg4MzM0MDAwMDMwMzE5MjAyMS0xMC0yMFQxOToyOTozMiswMzowMDA0MDMxMTUwNTAyMTU=")
expect(tags.to_base64).to eq("AQZNcnNvb2wCDzMxMDIyODgzMzQwMDAwMwMZMjAyMS0xMC0yMFQxOToyOTozMiswMzowMAQDMTE1BQIxNQ==")
end
end
end

0 comments on commit 09c0cf3

Please sign in to comment.