Class: Token

Inherits:
Object
  • Object
show all
Defined in:
lib/token.rb,
lib/token/version.rb

Overview

This class provides token creation and validation. It can be used as a singleton or by creating instances.

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =

The current release version of the library

'1.2.3'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Token

Creates a new token generator.

Options Hash (options):

  • :cipher (String)

    The cipher to use with OpenSSL. Defaults to 'AES-256-CFB'

  • :key (String)

    The key to use with OpenSSL. Defaults to a random key. Do not specify without also specifying cipher

  • :iv (String)

    The initialization vector to use with OpenSSL. Defaults to a random vector. Do not specify without also specifying cipher

  • :format (String)

    The string describing the format of the payloads. Should be in the format expected by Array.pack. Defaults to 'L'



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/token.rb', line 37

def initialize(options = {})

	# Check to see if there are custom cryptographic settings
	if options.has_key? :cipher
		@cipher = options[:cipher]
		cipher  = OpenSSL::Cipher.new(@cipher)
		@key    = options[:key] || cipher.random_key
		@iv     = options[:iv]  || cipher.random_iv

	# Otherwise, set the default cryptographic settings
	else
		@cipher = self.class.cipher
		@key    = self.class.key
		@iv     = self.class.iv
	end

	# Set the payload format
	@format = options[:format] || self.class.format
end

Class Attribute Details

.cipherObject

The class default cipher. Note that when setting the cipher, the key and initialization vector are cleared.



122
123
124
# File 'lib/token.rb', line 122

def cipher
  @cipher
end

.formatObject

The class default token payload format.



151
152
153
# File 'lib/token.rb', line 151

def format
  @format
end

.ivObject

The class default encryption initialization vector. Randomly generated when necessary if unset.



141
142
143
# File 'lib/token.rb', line 141

def iv
  @iv
end

.keyObject

The class default encryption key. Randomly generated when necessary if unset.



130
131
132
# File 'lib/token.rb', line 130

def key
  @key
end

Instance Attribute Details

#cipherObject

The cipher to use with OpenSSL



8
9
10
# File 'lib/token.rb', line 8

def cipher
  @cipher
end

#formatObject

The format of the payload. This string should be in the format expected by Array.pack



18
19
20
# File 'lib/token.rb', line 18

def format
  @format
end

#ivObject

The initialization vector to use with OpenSSL



14
15
16
# File 'lib/token.rb', line 14

def iv
  @iv
end

#keyObject

The key to use with OpenSSL



11
12
13
# File 'lib/token.rb', line 11

def key
  @key
end

Class Method Details

.generate(payload, expires) ⇒ Object

Generates a token using the class default cryptographic settings and payload format.

See Also:



161
162
163
# File 'lib/token.rb', line 161

def generate(payload, expires)
	instance.generate(payload, expires)
end

.resetObject

Resets the cipher to 'AES-256-CFB', the payload format to 'L', and the key and initialization vectors to random values.



175
176
177
178
179
180
181
# File 'lib/token.rb', line 175

def reset
	@cipher = 'AES-256-CFB'
	cipher  = OpenSSL::Cipher.new(@cipher)
	@key    = cipher.random_key
	@iv     = cipher.random_iv
	@format = 'L'
end

.verify(token) ⇒ Object

Verifies the validity of a token using the class default cryptographic settings and payload format.

See Also:



169
170
171
# File 'lib/token.rb', line 169

def verify(token)
	instance.verify(token)
end

Instance Method Details

#generate(payload, expires) ⇒ String

Creates a token consisting of the given payload and expiration date.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/token.rb', line 64

def generate(payload, expires)

	# Pack the token
	token = [
		expires.to_i,
		payload
	]
	token = token.flatten.pack("L#{@format}")

	# Prepend the token's hash
	token.prepend(Digest::SHA256.hexdigest(token))

	# Encrypt the token
	crypt = OpenSSL::Cipher.new(@cipher)
	crypt.encrypt
	crypt.key = @key
	crypt.iv  = @iv
	token     = crypt.update(token) + crypt.final
end

#verify(token) ⇒ Array

Verifies the validity of the given token and, if successful, returns the associated payload.

Raises:

  • (Token::Error)

    if the token fails to decrypt, is not signed properly, or is expired



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/token.rb', line 92

def verify(token)

	# Decrypt the token
	begin
		crypt = OpenSSL::Cipher.new(@cipher)
		crypt.decrypt
		crypt.key = @key
		crypt.iv  = @iv
		tok       = crypt.update(token) + crypt.final
	rescue
		raise Error, 'Session is invalid'
	end

	# Split the token
	tok = tok.unpack("A64L#{@format}")

	# Validate the token
	time_valid = Time.at(tok[1]) > Time.now
	hash       = Digest::SHA256.hexdigest(tok[1..-1].pack("L#{@format}"))
	hash_valid = hash == tok[0]
	raise Error, 'Session is invalid' unless time_valid && hash_valid

	# Return the payload
	tok.length == 3 ? tok.last : tok[2..-1]
end