Class: Bnet::Authenticator

Inherits:
Object
  • Object
show all
Defined in:
lib/bnet/authenticator.rb

Overview

The Battle.net authenticator

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(serial, secret) ⇒ Authenticator

Create a new authenticator with given serial and secret

Parameters:

  • serial (String)
  • secret (String)


34
35
36
37
38
39
40
41
42
43
# File 'lib/bnet/authenticator.rb', line 34

def initialize(serial, secret)
  serial = Bnet::Attributes::Serial.new serial
  secret = Bnet::Attributes::Secret.new secret
  restorecode = Bnet::Attributes::Restorecode.new serial, secret

  @serial = serial.to_s
  @secret = secret.to_s
  @restorecode = restorecode.to_s
  @region = serial.region
end

Instance Attribute Details

#regionSymbol (readonly)

Returns region.

Returns:

  • (Symbol)

    region



29
30
31
# File 'lib/bnet/authenticator.rb', line 29

def region
  @region
end

#restorecodeString (readonly)

Returns restoration code.

Returns:

  • (String)

    restoration code



25
26
27
# File 'lib/bnet/authenticator.rb', line 25

def restorecode
  @restorecode
end

#secretString (readonly)

Returns hexlified secret.

Returns:

  • (String)

    hexlified secret



21
22
23
# File 'lib/bnet/authenticator.rb', line 21

def secret
  @secret
end

#serialString (readonly)

Returns serial.

Returns:

  • (String)

    serial



17
18
19
# File 'lib/bnet/authenticator.rb', line 17

def serial
  @serial
end

Class Method Details

.get_token(secret, timestamp = nil) ⇒ String, Integer

Get token from given secret and timestamp

Parameters:

  • secret (String)

    hexified secret

  • timestamp (Integer) (defaults to: nil)

    UNIX timestamp in seconds, defaults to current time

Returns:

  • (String, Integer)

    token and the next timestamp token to change



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/bnet/authenticator.rb', line 105

def self.get_token(secret, timestamp = nil)
  secret = Bnet::Attributes::Secret.new secret

  current = (timestamp || Time.now.getutc.to_i) / 30
  digest = Digest::HMAC.digest([current].pack('Q>'), secret.binary, Digest::SHA1)
  start_position = digest[19].ord & 0xf

  token = digest[start_position, 4].unpack('L>')[0] & 0x7fffffff

  return '%08d' % (token % 100000000), (current + 1) * 30
end

.request_authenticator(region) ⇒ Bnet::Authenticator

Request a new authenticator from server

Parameters:

  • region (Symbol)

Returns:



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/bnet/authenticator.rb', line 48

def self.request_authenticator(region)
  k = create_one_time_pad(37)

  payload_plain = "\1" + k + region.to_s + CLIENT_MODEL.ljust(16, "\0")[0, 16]
  e = rsa_encrypt_bin(payload_plain)

  response_body = request_for('new serial', region, ENROLLMENT_REQUEST_PATH, e)

  decrypted = decrypt_response(response_body[8, 37], k)

  Authenticator.new(decrypted[20, 17], decrypted[0, 20])
end

.request_server_time(region) ⇒ Integer

Get server’s time

Parameters:

  • region (Symbol)

Returns:

  • (Integer)

    server timestamp in seconds



95
96
97
98
# File 'lib/bnet/authenticator.rb', line 95

def self.request_server_time(region)
  server_time_big_endian = request_for('server time', region, TIME_REQUEST_PATH)
  server_time_big_endian.unpack('Q>')[0].to_f / 1000
end

.restore_authenticator(serial, restorecode) ⇒ Bnet::Authenticator

Restore an authenticator from server

Parameters:

  • serial (String)
  • restorecode (String)

Returns:



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/bnet/authenticator.rb', line 65

def self.restore_authenticator(serial, restorecode)
  serial = Bnet::Attributes::Serial.new serial
  restorecode = Bnet::Attributes::Restorecode.new restorecode

  # stage 1
  challenge = request_for('restore (stage 1)',
                          serial.region,
                          RESTORE_INIT_REQUEST_PATH,
                          serial.normalized)

  # stage 2
  key = create_one_time_pad(20)

  digest = Digest::HMAC.digest(serial.normalized + challenge,
                               restorecode.binary,
                               Digest::SHA1)

  payload = serial.normalized + rsa_encrypt_bin(digest + key)

  response_body = request_for('restore (stage 2)',
                              serial.region,
                              RESTORE_VALIDATE_REQUEST_PATH,
                              payload)

  Authenticator.new(serial, decrypt_response(response_body, key))
end

Instance Method Details

#get_token(timestamp = nil) ⇒ String, Integer

Get authenticator’s token from given timestamp

Parameters:

  • timestamp (Integer) (defaults to: nil)

    UNIX timestamp in seconds, defaults to current time

Returns:

  • (String, Integer)

    token and the next timestamp token to change



121
122
123
# File 'lib/bnet/authenticator.rb', line 121

def get_token(timestamp = nil)
  self.class.get_token(secret, timestamp)
end

#to_hashHash

Hash representation of this authenticator

Returns:

  • (Hash)


127
128
129
130
131
132
133
134
# File 'lib/bnet/authenticator.rb', line 127

def to_hash
  {
    :serial => serial,
    :secret => secret,
    :restorecode => restorecode,
    :region => region,
  }
end

#to_sString

String representation of this authenticator

Returns:

  • (String)


138
139
140
# File 'lib/bnet/authenticator.rb', line 138

def to_s
  to_hash.to_s
end