tibia-client/modules/gamelib/protocollogin.lua

261 lines
7.0 KiB
Lua
Raw Normal View History

2012-06-26 00:13:30 +02:00
-- @docclass
ProtocolLogin = extends(Protocol, "ProtocolLogin")
2012-06-05 23:27:37 +02:00
LoginServerError = 10
LoginServerTokenSuccess = 12
LoginServerTokenError = 13
LoginServerUpdate = 17
LoginServerMotd = 20
LoginServerUpdateNeeded = 30
LoginServerSessionKey = 40
LoginServerCharacterList = 100
LoginServerExtendedCharacterList = 101
-- Since 10.76
LoginServerRetry = 10
LoginServerErrorNew = 11
function ProtocolLogin:login(host, port, accountName, accountPassword, authenticatorToken, stayLogged)
2012-07-26 08:10:28 +02:00
if string.len(host) == 0 or port == nil or port == 0 then
2013-02-21 21:31:47 +01:00
signalcall(self.onLoginError, self, tr("You must enter a valid server address and port."))
2012-07-26 08:10:28 +02:00
return
end
self.accountName = accountName
self.accountPassword = accountPassword
self.authenticatorToken = authenticatorToken
self.stayLogged = stayLogged
self.connectCallback = self.sendLoginPacket
2012-07-26 08:10:28 +02:00
self:connect(host, port)
end
2012-07-26 08:10:28 +02:00
function ProtocolLogin:cancelLogin()
self:disconnect()
end
function ProtocolLogin:sendLoginPacket()
2012-06-05 23:27:37 +02:00
local msg = OutputMessage.create()
2013-12-23 23:42:58 +01:00
msg:addU8(ClientOpcodes.ClientEnterAccount)
msg:addU16(g_game.getOs())
msg:addU16(g_game.getProtocolVersion())
if g_game.getFeature(GameClientVersion) then
msg:addU32(g_game.getClientVersion())
end
2012-06-05 23:27:37 +02:00
if g_game.getFeature(GameContentRevision) then
msg:addU16(g_things.getContentRevision())
msg:addU16(0)
else
msg:addU32(g_things.getDatSignature())
end
2012-06-21 19:54:20 +02:00
msg:addU32(g_sprites.getSprSignature())
msg:addU32(PIC_SIGNATURE)
2012-06-05 23:27:37 +02:00
if g_game.getFeature(GamePreviewState) then
msg:addU8(0)
end
local offset = msg:getMessageSize()
if g_game.getFeature(GameLoginPacketEncryption) then
2013-12-23 23:42:58 +01:00
-- first RSA byte must be 0
msg:addU8(0)
-- xtea key
self:generateXteaKey()
local xteaKey = self:getXteaKey()
msg:addU32(xteaKey[1])
msg:addU32(xteaKey[2])
msg:addU32(xteaKey[3])
msg:addU32(xteaKey[4])
end
2012-06-05 23:27:37 +02:00
if g_game.getFeature(GameAccountNames) then
2012-07-26 08:10:28 +02:00
msg:addString(self.accountName)
2012-06-05 23:27:37 +02:00
else
2012-07-26 08:10:28 +02:00
msg:addU32(tonumber(self.accountName))
2012-06-05 23:27:37 +02:00
end
msg:addString(self.accountPassword)
if self.getLoginExtendedData then
local data = self:getLoginExtendedData()
msg:addString(data)
end
local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
assert(paddingBytes >= 0)
for i = 1, paddingBytes do
msg:addU8(math.random(0, 0xff))
end
if g_game.getFeature(GameLoginPacketEncryption) then
msg:encryptRsa()
end
if g_game.getFeature(GameOGLInformation) then
msg:addU8(1) --unknown
msg:addU8(1) --unknown
if g_game.getClientVersion() >= 1072 then
msg:addString(string.format('%s %s', g_graphics.getVendor(), g_graphics.getRenderer()))
else
msg:addString(g_graphics.getRenderer())
end
msg:addString(g_graphics.getVersion())
end
-- add RSA encrypted auth token
if g_game.getFeature(GameAuthenticator) then
offset = msg:getMessageSize()
-- first RSA byte must be 0
msg:addU8(0)
msg:addString(self.authenticatorToken)
if g_game.getFeature(GameSessionKey) then
msg:addU8(booleantonumber(self.stayLogged))
end
paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
assert(paddingBytes >= 0)
for i = 1, paddingBytes do
msg:addU8(math.random(0, 0xff))
end
msg:encryptRsa()
end
if g_game.getFeature(GameProtocolChecksum) then
self:enableChecksum()
end
2012-06-05 23:27:37 +02:00
2012-07-26 08:10:28 +02:00
self:send(msg)
if g_game.getFeature(GameLoginPacketEncryption) then
self:enableXteaEncryption()
end
2012-07-26 08:10:28 +02:00
self:recv()
2012-06-05 23:27:37 +02:00
end
function ProtocolLogin:onConnect()
2013-02-22 22:49:36 +01:00
self.gotConnection = true
self:connectCallback()
self.connectCallback = nil
2012-06-05 23:27:37 +02:00
end
function ProtocolLogin:onRecv(msg)
while not msg:eof() do
local opcode = msg:getU8()
if opcode == LoginServerErrorNew then
self:parseError(msg)
elseif opcode == LoginServerError then
2012-06-05 23:27:37 +02:00
self:parseError(msg)
elseif opcode == LoginServerMotd then
self:parseMotd(msg)
elseif opcode == LoginServerUpdateNeeded then
2013-02-21 21:31:47 +01:00
signalcall(self.onLoginError, self, tr("Client needs update."))
elseif opcode == LoginServerTokenSuccess then
local unknown = msg:getU8()
elseif opcode == LoginServerTokenError then
-- TODO: prompt for token here
local unknown = msg:getU8()
signalcall(self.onLoginError, self, tr("Invalid authentification token."))
2012-06-05 23:27:37 +02:00
elseif opcode == LoginServerCharacterList then
self:parseCharacterList(msg)
elseif opcode == LoginServerExtendedCharacterList then
self:parseExtendedCharacterList(msg)
elseif opcode == LoginServerUpdate then
local signature = msg:getString()
signalcall(self.onUpdateNeeded, self, signature)
elseif opcode == LoginServerSessionKey then
self:parseSessionKey(msg)
2012-06-05 23:27:37 +02:00
else
self:parseOpcode(opcode, msg)
end
end
self:disconnect()
end
function ProtocolLogin:parseError(msg)
local errorMessage = msg:getString()
2013-02-21 21:31:47 +01:00
signalcall(self.onLoginError, self, errorMessage)
2012-06-05 23:27:37 +02:00
end
function ProtocolLogin:parseMotd(msg)
local motd = msg:getString()
signalcall(self.onMotd, self, motd)
end
function ProtocolLogin:parseSessionKey(msg)
local sessionKey = msg:getString()
signalcall(self.onSessionKey, self, sessionKey)
end
2012-06-05 23:27:37 +02:00
function ProtocolLogin:parseCharacterList(msg)
local characters = {}
if g_game.getClientVersion() > 1010 then
local worlds = {}
local worldsCount = msg:getU8()
for i=1, worldsCount do
local world = {}
local worldId = msg:getU8()
world.worldName = msg:getString()
2013-11-10 06:17:49 +01:00
world.worldIp = msg:getString()
world.worldPort = msg:getU16()
world.previewState = msg:getU8()
worlds[worldId] = world
end
local charactersCount = msg:getU8()
for i=1, charactersCount do
local character = {}
local worldId = msg:getU8()
character.name = msg:getString()
character.worldName = worlds[worldId].worldName
character.worldIp = worlds[worldId].worldIp
character.worldPort = worlds[worldId].worldPort
character.previewState = worlds[worldId].previewState
characters[i] = character
end
else
local charactersCount = msg:getU8()
for i=1,charactersCount do
local character = {}
character.name = msg:getString()
character.worldName = msg:getString()
character.worldIp = iptostring(msg:getU32())
character.worldPort = msg:getU16()
if g_game.getFeature(GamePreviewState) then
character.previewState = msg:getU8()
end
characters[i] = character
end
2012-06-05 23:27:37 +02:00
end
local account = {}
account.premDays = msg:getU16()
signalcall(self.onCharacterList, self, characters, account)
end
function ProtocolLogin:parseExtendedCharacterList(msg)
local characters = msg:getTable()
local account = msg:getTable()
local otui = msg:getString()
signalcall(self.onCharacterList, self, characters, account, otui)
2012-06-05 23:27:37 +02:00
end
function ProtocolLogin:parseOpcode(opcode, msg)
signalcall(self.onOpcode, self, opcode, msg)
end
2013-02-21 21:31:47 +01:00
function ProtocolLogin:onError(msg, code)
2013-02-27 20:24:32 +01:00
local text = translateNetworkError(code, self:isConnecting(), msg)
2013-02-22 22:49:36 +01:00
signalcall(self.onLoginError, self, text)
2013-02-21 21:31:47 +01:00
end