Module: Philiprehberger::Base64Url

Defined in:
lib/philiprehberger/base64_url.rb,
lib/philiprehberger/base64_url/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
'0.5.0'

Class Method Summary collapse

Class Method Details

.byte_length(encoded) ⇒ Integer

Calculate the decoded byte length from an encoded string without decoding.

Parameters:

  • encoded (String)

    URL-safe Base64 string

Returns:

  • (Integer)

    number of bytes in the decoded output



84
85
86
87
88
89
90
# File 'lib/philiprehberger/base64_url.rb', line 84

def self.byte_length(encoded)
  return 0 if encoded.nil? || encoded.empty?

  stripped = encoded.delete('=')
  padding = (4 - (stripped.length % 4)) % 4
  ((stripped.length + padding) * 3 / 4) - padding
end

.decode(data) ⇒ String

Decode URL-safe Base64 data

Parameters:

  • data (String)

    the Base64 string to decode

Returns:

  • (String)

    decoded data

Raises:

  • (Error)

    if data cannot be decoded



25
26
27
28
29
# File 'lib/philiprehberger/base64_url.rb', line 25

def self.decode(data)
  Base64.urlsafe_decode64(data)
rescue ArgumentError => e
  raise Error, "invalid Base64: #{e.message}"
end

.decode_json(str) ⇒ Hash

Decode a URL-safe Base64 string and parse as JSON

Parameters:

  • str (String)

    the Base64 encoded JSON string

Returns:

  • (Hash)

    the decoded hash

Raises:

  • (Error)

    if string cannot be decoded or parsed



44
45
46
47
48
# File 'lib/philiprehberger/base64_url.rb', line 44

def self.decode_json(str)
  JSON.parse(decode(str))
rescue JSON::ParserError => e
  raise Error, "invalid JSON: #{e.message}"
end

.decode_to_file(encoded, path) ⇒ void

This method returns an undefined value.

Decode a URL-safe Base64 string and write to a file.

Parameters:

  • encoded (String)

    URL-safe Base64 string

  • path (String)

    output file path

Raises:

  • (Error)

    if the string cannot be decoded



108
109
110
# File 'lib/philiprehberger/base64_url.rb', line 108

def self.decode_to_file(encoded, path)
  File.binwrite(path, decode(encoded))
end

.encode(data, padding: false) ⇒ String

Encode data to URL-safe Base64

Parameters:

  • data (String)

    the data to encode

  • padding (Boolean) (defaults to: false)

    whether to include padding (default: false)

Returns:

  • (String)

    URL-safe Base64 encoded string



16
17
18
# File 'lib/philiprehberger/base64_url.rb', line 16

def self.encode(data, padding: false)
  Base64.urlsafe_encode64(data, padding: padding)
end

.encode_file(path, padding: false) ⇒ String

Encode a file’s contents to URL-safe Base64.

Parameters:

  • path (String)

    path to the file

  • padding (Boolean) (defaults to: false)

    whether to include padding (default: false)

Returns:

  • (String)

    URL-safe Base64 encoded contents

Raises:

  • (Errno::ENOENT)

    if the file does not exist



98
99
100
# File 'lib/philiprehberger/base64_url.rb', line 98

def self.encode_file(path, padding: false)
  encode(File.binread(path), padding: padding)
end

.encode_json(hash) ⇒ String

Encode a hash as JSON then URL-safe Base64

Parameters:

  • hash (Hash)

    the hash to encode

Returns:

  • (String)

    URL-safe Base64 encoded JSON string



35
36
37
# File 'lib/philiprehberger/base64_url.rb', line 35

def self.encode_json(hash)
  encode(JSON.generate(hash))
end

.from_std(data) ⇒ String

Convert a standard Base64 string to a URL-safe Base64 string.

Replaces ‘+` with `-`, `/` with `_`, and strips trailing `=` padding. Does not validate or decode the input.

Parameters:

  • data (String)

    standard Base64 string

Returns:

  • (String)

    URL-safe Base64 string



132
133
134
# File 'lib/philiprehberger/base64_url.rb', line 132

def self.from_std(data)
  data.tr('+/', '-_').delete('=')
end

.secure_compare(a, b) ⇒ Boolean

Constant-time comparison of two Base64 strings.

Prevents timing attacks by always comparing all bytes.

Parameters:

  • a (String)

    first string

  • b (String)

    second string

Returns:

  • (Boolean)

    true if strings are equal



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/philiprehberger/base64_url.rb', line 68

def self.secure_compare(a, b)
  return false unless a.bytesize == b.bytesize

  left = a.unpack('C*')
  right = b.unpack('C*')
  result = 0

  left.each_with_index { |byte, i| result |= byte ^ right[i] }

  result.zero?
end

.to_std(data) ⇒ String

Convert a URL-safe Base64 string to a standard Base64 string.

Replaces ‘-` with `+`, `_` with `/`, and adds `=` padding so the length is a multiple of 4. Does not validate or decode the input.

Parameters:

  • data (String)

    URL-safe Base64 string

Returns:

  • (String)

    standard Base64 string



119
120
121
122
123
# File 'lib/philiprehberger/base64_url.rb', line 119

def self.to_std(data)
  converted = data.tr('-_', '+/')
  padding = (4 - (converted.length % 4)) % 4
  converted + ('=' * padding)
end

.valid?(data) ⇒ Boolean

Check if a string is valid URL-safe Base64

Parameters:

  • data (String)

    the string to validate

Returns:

  • (Boolean)

    true if valid, false otherwise



54
55
56
57
58
59
# File 'lib/philiprehberger/base64_url.rb', line 54

def self.valid?(data)
  decode(data)
  true
rescue Error
  false
end