Class: BB::Crypto::ControlToken

Inherits:
Object
  • Object
show all
Defined in:
lib/blackbox/crypto.rb

Overview

Secure Control Token.

Class Method Summary (collapse)

Class Method Details

+ (String) create(op, args, expire_in = 900, key = ENV['CONTROLTOKEN_SECRET'], cipher_type = 'aes-256-cbc')

Encode and encrypt an urlsafe ControlToken.

Parameters:

  • op (String)

    Operation id

  • args (Array)

    Arguments (Strings)

  • expire_in (Fixnum) (defaults to: 900)
  • key (String) (defaults to: ENV['CONTROLTOKEN_SECRET'])

    Encryption key

  • cipher_type (String) (defaults to: 'aes-256-cbc')

    OpenSSL cipher

Returns:

  • (String)

    ControlToken (urlsafe base64)

Raises:

  • (ArgumentError)


109
110
111
112
113
114
115
# File 'lib/blackbox/crypto.rb', line 109

def create(op, args, expire_in = 900, key = ENV['CONTROLTOKEN_SECRET'], cipher_type = 'aes-256-cbc')
  raise ArgumentError, 'key can not be blank' if key.nil? || key.empty?
  # If you're reading this in the year 2038: Hi there! :-)
  [Time.now.to_i + expire_in].pack('l<')
  body = ([[Time.now.to_i + expire_in].pack('l<'), op] + args).join("\x00")
  BB::Crypto.encrypt_urlsafe_base64(body, key, cipher_type)
end

+ (Hash) parse(token, key = ENV['CONTROLTOKEN_SECRET'], force = false, cipher_type = 'aes-256-cbc')

Decrypt and parse an urlsafe ControlToken.

Parameters:

  • token (String)

    Input String (urlsafe base64)

  • key (String) (defaults to: ENV['CONTROLTOKEN_SECRET'])

    Encryption key

  • force (Boolean) (defaults to: false)

    Decode expired token (suppress ArgumentError)

  • cipher_type (String) (defaults to: 'aes-256-cbc')

    OpenSSL cipher

Returns:

  • (Hash)

    Token payload

Raises:

  • (ArgumentError)


124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/blackbox/crypto.rb', line 124

def parse(token, key = ENV['CONTROLTOKEN_SECRET'], force = false, cipher_type = 'aes-256-cbc')
  raise ArgumentError, 'key can not be blank' if key.nil? || key.empty?
  body = BB::Crypto.decrypt_urlsafe_base64(token, key, cipher_type)
  valid_until, op, *args = body.split("\x00")
  valid_until = valid_until.unpack('l<')[0]
  expired = Time.now.to_i > valid_until
  if expired && !force
    raise ArgumentError, "Token expired at #{Time.at(valid_until)} (#{ChronicDuration.output(Time.now.to_i - valid_until)} ago)"
  end
  { valid_until: valid_until,
    op: op,
    args: args,
    expired: expired }
end