module HealthCards::ChunkingUtils

Split up a JWS into chunks if encoded size is above QR Code Size constraint

Constants

MAX_CHUNK_SIZE
MAX_SINGLE_JWS_SIZE

Public Instance Methods

jws_to_qr_chunks(jws) click to toggle source

Splits jws into chunks and converts each string into numeric

# File lib/health_cards/chunking_utils.rb, line 21
def jws_to_qr_chunks(jws)
  chunks = split_jws(jws.to_s).map { |c| convert_jws_to_numeric(c) }

  # if 1 chunk, attach prefix shc:/
  # if multiple chunks, attach prefix shc:/$orderNumber/$totalChunkCount
  if chunks.length == 1
    chunks[0] = "shc:/#{chunks[0]}"
  else
    chunks.map!.with_index(1) { |ch, i| "shc:/#{i}/#{chunks.length}/#{ch}" }
  end
  chunks
end
qr_chunks_to_jws(qr_chunks) click to toggle source

Assemble jws from qr code chunks

# File lib/health_cards/chunking_utils.rb, line 35
def qr_chunks_to_jws(qr_chunks)
  if qr_chunks.length == 1
    # Strip off shc:/ and convert numeric jws
    numeric_jws = qr_chunks[0].delete_prefix('shc:/')
    convert_numeric_jws numeric_jws
  else
    ordered_qr_chunks = strip_prefix_and_sort qr_chunks
    ordered_qr_chunks.map { |c| convert_numeric_jws(c) }.join
  end
end
split_jws(jws) click to toggle source
# File lib/health_cards/chunking_utils.rb, line 10
def split_jws(jws)
  if jws.length <= MAX_SINGLE_JWS_SIZE
    [jws]
  else
    chunk_count = (jws.length / MAX_CHUNK_SIZE.to_f).ceil
    chunk_size  = (jws.length / chunk_count.to_f).ceil
    jws.scan(/.{1,#{chunk_size}}/)
  end
end

Private Instance Methods

convert_jws_to_numeric(jws) click to toggle source

Each character ā€œcā€ of the jws is converted into a sequence of two digits by taking c.ord - 45

# File lib/health_cards/chunking_utils.rb, line 49
def convert_jws_to_numeric(jws)
  jws.chars.map { |c| format('%02d', c.ord - 45) }.join
end
convert_numeric_jws(numeric_jws) click to toggle source
# File lib/health_cards/chunking_utils.rb, line 53
def convert_numeric_jws(numeric_jws)
  result_jws = ''.dup
  numeric_jws.chars.each_slice(2) do |a, b|
    result_jws << ((a + b).to_i + 45).chr
  end
  result_jws
end
strip_prefix_and_sort(qr_chunks) click to toggle source
# File lib/health_cards/chunking_utils.rb, line 61
def strip_prefix_and_sort(qr_chunks)
  # Multiple QR codes are prefixed with 'shc:/C/N' where C is the index and N is the total number of chunks
  # Sorts chunks by C
  sorted_chunks = qr_chunks.sort_by { |c| c[%r{/(.*?)/}, 1].to_i }
  # Strip prefix
  sorted_chunks.map { |c| c.sub(%r{shc:/(.*?)/(.*?)/}, '') }
end