improve: https/http login (#647)

This commit is contained in:
Renato Foot Guimarães Costallat 2024-03-07 13:04:04 -03:00 committed by GitHub
parent d46fdf532a
commit 00cd5e6d36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 916 additions and 567 deletions

View file

@ -3,7 +3,8 @@
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
## Behaviour
## Behavior
### **Actual**
Do this and that doesn't happens

View file

@ -68,7 +68,7 @@ jobs:
name: otclient-${{ matrix.buildtype }}-${{ github.sha }}
path: |
${{ github.workspace }}/otclient.exe
- name: Create and Upload Artifact (dlls)
uses: actions/upload-artifact@main
with:

View file

@ -5,7 +5,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \
RUN apt-get update && apt-get install -y --no-install-recommends \
git cmake curl zip unzip tar automake ca-certificates build-essential \
libglew-dev libx11-dev autoconf libtool pkg-config tzdata \
libglew-dev libx11-dev autoconf libtool pkg-config tzdata libssl3 \
&& dpkg-reconfigure --frontend noninteractive tzdata \
&& apt-get clean && apt-get autoclean

View file

@ -1,21 +0,0 @@
# Try to find the OpenSSL library
# OPENSSL_FOUND - system has OpenSSL
# OPENSSL_INCLUDE_DIR - the OpenSSL include directory
# OPENSSL_LIBRARY - the OpenSSL library
FIND_PATH(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h PATH_SUFFIXES include openssl-1.0)
SET(_OPENSSL_STATIC_LIBS libssl.a ssl.a)
SET(_OPENSSL_SHARED_LIBS libssl ssl)
SET(_OPENSSL_CRYPTO_STATIC_LIBS libcrypto.a crypto.a)
SET(_OPENSSL_CRYPTO_SHARED_LIBS libcrypto crypto)
IF(USE_STATIC_LIBS)
FIND_LIBRARY(OPENSSL_LIBRARY NAMES ${_OPENSSL_STATIC_LIBS} ${_OPENSSL_SHARED_LIBS} PATH_SUFFIXES openssl-1.0)
FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARY NAMES ${_OPENSSL_CRYPTO_STATIC_LIBS} ${_OPENSSL_CRYPTO_SHARED_LIBS} PATH_SUFFIXES openssl-1.0)
ELSE()
FIND_LIBRARY(OPENSSL_LIBRARY NAMES ${_OPENSSL_SHARED_LIBS} ${_OPENSSL_STATIC_LIBS} PATH_SUFFIXES openssl-1.0)
FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARY NAMES ${_OPENSSL_CRYPTO_SHARED_LIBS} ${_OPENSSL_CRYPTO_STATIC_LIBS} PATH_SUFFIXES openssl-1.0)
ENDIF()
SET(OPENSSL_LIBRARIES ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSSL DEFAULT_MSG OPENSSL_LIBRARIES OPENSSL_INCLUDE_DIR)
MARK_AS_ADVANCED(OPENSSL_LIBRARIES OPENSSL_LIBRARY OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR)

View file

@ -1,16 +0,0 @@
# Try to find the ZLIB library
# ZLIB_FOUND - system has ZLIB
# ZLIB_INCLUDE_DIR - the ZLIB include directory
# ZLIB_LIBRARY - the ZLIB library
FIND_PATH(ZLIB_INCLUDE_DIR NAMES zlib.h)
SET(_ZLIB_STATIC_LIBS libz.a libzlib.a zlib1.a)
SET(_ZLIB_SHARED_LIBS libz.dll.a zdll zlib zlib1 z)
IF(USE_STATIC_LIBS)
FIND_LIBRARY(ZLIB_LIBRARY NAMES ${_ZLIB_STATIC_LIBS} ${_ZLIB_SHARED_LIBS})
ELSE()
FIND_LIBRARY(ZLIB_LIBRARY NAMES ${_ZLIB_SHARED_LIBS} ${_ZLIB_STATIC_LIBS})
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB DEFAULT_MSG ZLIB_LIBRARY ZLIB_INCLUDE_DIR)
MARK_AS_ADVANCED(ZLIB_LIBRARY ZLIB_INCLUDE_DIR)

View file

@ -9,16 +9,17 @@ locale = {
-- As traduções devem vir sempre em ordem alfabética.
translation = {
["(ERROR %d)"] = "(ERRO %d)",
["%d of experience per hour"] = "%d de experiência por hora",
["%s has finished the request"] = "%s finalizou o pedido",
["%s has logged in."] = "%s entrou.",
["%s has logged out."] = "%s saiu.",
["%s of experience left"] = "%s de experiência faltando",
["%s of experience per hour"] = "%s experiência por hora",
["%s: (use object on target)"] = "%s: (usar objeto no alvo)",
["%s: (use object on yourself)"] = "%s: (usar objeto em si)",
["%s: (use object with crosshair)"] = "%s: (usar objeto com mira)",
["%s: (use object)"] = "%s: (usar objeto)",
["(ERROR %d)"] = "(ERRO %d)",
["1a) Offensive Name"] = "1a) Nome ofensivo",
["1b) Invalid Name Format"] = "1b) Nome com formato inválido",
["1c) Unsuitable Name"] = "1c) Nome não adequado",
@ -94,6 +95,7 @@ locale = {
["Channel appended to %s"] = "Canais acrescentados a %s",
["Channels"] = "Canais",
["Character List"] = "Lista de personagens",
["Character"] = "Personagem",
["Classic control"] = "Controle clássico",
["Clear current message window"] = "Apagar mensagens",
["Clear Messages"] = "Limpar mensagens",
@ -107,6 +109,7 @@ locale = {
["Comment"] = "Comentário",
["Connecting to game server..."] = "Conectando no servidor do jogo...",
["Connecting to login server..."] = "Conectando no servidor de autenticação...",
["Connecting to login server...\nServer: [%s]"] = "Conectando no servidor de autenticação...\nServidor: [%s]",
["Connection Error"] = "Erro de Conexão",
["Connection failed the server address does not exist."] = "Conexão falhou, servidor não existe.",
["Connection failed, the server address does not exist."] = false,
@ -139,7 +142,6 @@ locale = {
["Details"] = "Detalhes",
["Disable chat mode allow to walk using WASD"] = "Desativar modo de chat permite andar usando WASD",
["Disable chat mode, allow to walk using WASD"] = false,
["Disable chat mode, allow to walk using WASD"] = false,
["Disable Shared Experience"] = "Desativar experiência compartilhada",
["Dismount"] = "Desmontar",
["Display connection speed to the server (milliseconds)"] = "Exibir a velocidade de conexão com o servidor (milisegundos)",
@ -154,14 +156,15 @@ locale = {
["Draw Viewport Edge"] = "Desenhar borda da janela de visualização",
["Druid"] = "Druid",
["Edit %s"] = "Editar %s",
["Edit hotkey text"] = false,
["Edit hotkey text:"] = "Editar texto do atalho",
["Edit hotkey text"] = false,
["Edit List"] = "Editar lista",
["Edit Text"] = "Editar Texto",
["Edit VIP list entry"] = false,
["Enable audio"] = "Ativar áudio",
["Enable chat mode"] = false,
["Enable dash walking"] = "Ativar andar rápido",
["Enable HTTP login"] = "Ativar login HTTP",
["Enable lights"] = "Ativar luzes",
["Enable music sound"] = "Ativar música",
["Enable music"] = "Ativar musica",
@ -218,6 +221,7 @@ locale = {
["Hotkey delay: %dms"] = false,
["Hotkey delay: %sms"] = false,
["Hotkeys"] = "Atalhos",
["If login fails using HTTPS (encrypted) try with HTTP (unencrypted)"] = "Se o login falhar utilizando HTTPS(criptografado) tente com HTTP(sem criptografia)",
["If you shut down the program, your character might stay in the game.\nClick on 'Logout' to ensure that you character leaves the game properly.\nClick on 'Exit' if you want to exit the program without logging out your character."] = "Se você desligar o programa o seu personagem pode continuar no jogo.\nClique em 'Sair' para assegurar que seu personagem saia do jogo adequadamente.\nClique em 'Forçar Saida' para fechar o programa sem desconectar seu personagem.",
["Ignore capacity"] = "Ignorar capacidade",
["Ignore equipped"] = "Ignorar equipado",
@ -226,8 +230,8 @@ locale = {
["Ignore Private Messages"] = "Ignorar mensagens privadas",
["Ignore Yelling"] = "Ignorar gritos",
["Ignore"] = "Ignorar",
["Ignored Players"] = false,
["Ignored players:"] = "Joadores ignorados:",
["Ignored Players"] = false,
["Interface framerate limit: %s"] = "Limite da taxa de quadros da interface: %s",
["Invalid authentification token."] = false,
["Inventory"] = "Inventário",
@ -287,6 +291,7 @@ locale = {
["No"] = "Não",
["Notation"] = "Notação",
["Notify-Login"] = false,
["Now you will gain 50%% more experience"] = "Agora você ganhará 50%% mais experiência",
["NPC Trade"] = "Troca com NPC",
["Offer History"] = "Histórico de ofertas",
["Offer Type"] = "Tipo de oferta",
@ -294,8 +299,8 @@ locale = {
["Offline Training"] = "Treino Offline",
["Ok"] = "Ok",
["on %s.\n"] = "em %s.\n",
["Open a private message channel"] = false,
["Open a private message channel:"] = "Abrir um canal privado:",
["Open a private message channel"] = false,
["Open charlist automatically when starting client"] = "Abrir lista de personagens ao iniciar o cliente",
["Open in new window"] = "Abrir em nova janela",
["Open new channel"] = "Abrir novo canal",
@ -317,8 +322,8 @@ locale = {
["Please wait"] = "Por favor, espere",
["Please, press the key you wish to add onto your hotkeys manager"] = "Por favor, pressione a tecla que você deseja\nadicionar no gerenciador de atalhos",
["Port"] = "Porta",
["Position"] = "Posição",
["Position: %i %i %i"] = "Posição: %i %i %i",
["Position"] = "Posição",
["Premium Account (%s) days left"] = "Conta Premium (%s) dias faltando",
["Premium"] = "Premium",
["Price"] = "Preço",
@ -358,6 +363,7 @@ locale = {
["Search"] = "Procurar",
["Secondary"] = "Secundário",
["Select all"] = false,
["Select monster"] = "Selecione o monstro",
["Select object"] = "Selecionar objeto",
["Select Outfit"] = "Selecionar Roupa",
["Select your language"] = "Selecione sua língua",
@ -370,9 +376,10 @@ locale = {
["Send automatically"] = "Enviar automaticamente",
["Send Message"] = "Enviar Mensagem",
["Send"] = "Enviar",
["Server List"] = "Lista de Servidores",
["Server list"] = "Lista de servidores",
["Server List"] = "Lista de Servidores",
["Server Log"] = "Registro do servidor",
["Server: %s"] = "Servidor: %s",
["Server"] = "Servidor",
["Set Outfit"] = "Escolher Roupa",
["Shielding"] = "Defesa",
@ -410,6 +417,7 @@ locale = {
["Statement Report"] = "Afirmar Relato",
["Statement"] = "Afirmação",
["Statistics"] = "Estatísticas",
["Status"] = "Condição",
["Stay logged during session"] = false,
["Stop Attack"] = "Parar de Atacar",
["Stop Follow"] = "Parar de Seguir",
@ -451,13 +459,14 @@ locale = {
["Will boost your walk on high speed characters"] = "Irá melhorar o andar de persnagens rápidos",
["Will detect when to use diagonal step based on the\nkeys you are pressing"] = "Detectar quando usar o passo diagonal\nbaseado nas teclas pressionadas",
["With crosshair"] = "Com mira",
["World"] = "Mundo",
["Yes"] = "Sim",
["You are bleeding"] = "Você está sangrando",
["You are burning"] = "Você está queimando",
["You are cursed"] = "Você está amaldiçoado",
["You are dazzled"] = "Você está deslumbrado",
["You are dead"] = "Você está morto",
["You are dead."] = "Você está morto.",
["You are dead"] = "Você está morto",
["You are drowning"] = "Você está se afogando",
["You are drunk"] = "Você está bêbado",
["You are electrified"] = "Você está eletrificado",
@ -470,7 +479,9 @@ locale = {
["You are strengthened"] = "Você está reforçado",
["You are within a protection zone"] = "Você está dentro de uma zona de proteção",
["You can enter new text."] = "Você pode entrar com um novo texto.",
["You don't may receive experience and loot from monsters"] = "Você talvez não possa receber experiencia e loot dos monstros",
["You have %d%% to advance to level %d."] = "Você tem %d%% para avançar para o nível %d.",
["You have %s hours and %s minutes left"] = "Você tem %s horas e %s minutos restando",
["You have %s percent to go"] = "Você tem %s porcento para avançar",
["You have %s percent"] = "Você tem %s porcento",
["You may not logout during a fight"] = "Você não pode sair durante um combate",
@ -482,6 +493,7 @@ locale = {
["You must select an action."] = false,
["You read the following, written by \n%s\n"] = "Você lê o seguinte, escrito por \n%s\n",
["You read the following, written on \n%s.\n"] = "Você lê o seguinte, escrito em \n%s.\n",
["You will not gain 50%% more experience because you aren't premium player, now you receive only 1x experience points"] = "Você não ganhará 50%% mais experiencia pois você não é premium, agora você receberá apenas 1x pontos de experiência",
["Your Capacity"] = "Sua capacidade",
["Your character health is %d out of %d."] = "A vida do seu personagem é %d de %d.",
["Your character mana is %d out of %d."] = "A mana do seu personagem é %d de %d.",

View file

@ -96,7 +96,7 @@ CharacterWidget < UIWidget
color: #bbbbbb
anchors.top: parent.top
anchors.left: parent.left
margin-left: 300
margin-left: 350
font: verdana-11px-monochrome
text-auto-resize: true
background-color: alpha
@ -114,7 +114,7 @@ CharacterWidget < UIWidget
color: #bbbbbb
anchors.top: parent.top
anchors.left: parent.left
margin-left: 350
margin-left: 410
font: verdana-11px-monochrome
text-auto-resize: true
background-color: alpha
@ -199,7 +199,7 @@ MainWindow
end
FlatLabel
width: 50
width: 100
anchors.left: parent.left
anchors.top: characters.top
margin-left: 250
@ -210,10 +210,10 @@ MainWindow
end
FlatLabel
width: 50
width: 60
anchors.left: parent.left
anchors.top: characters.top
margin-left: 300
margin-left: 350
!text: tr('Level') .. ''
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
@ -224,7 +224,7 @@ MainWindow
width: 150
anchors.left: parent.left
anchors.top: characters.top
margin-left: 350
margin-left: 410
!text: tr('Vocation') .. ''
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
@ -232,9 +232,10 @@ MainWindow
end
FlatLabel
width: 201
width: 200
anchors.right: characters.right
anchors.top: characters.top
margin-left: 550
!text: tr('World') .. ''
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
@ -260,16 +261,6 @@ MainWindow
self:hide()
end
VerticalSeparator
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: prev.bottom
margin-left: 299
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
self:hide()
end
VerticalSeparator
anchors.left: parent.left
anchors.top: parent.top
@ -284,7 +275,17 @@ MainWindow
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: prev.bottom
margin-left: 499
margin-left: 409
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
self:hide()
end
VerticalSeparator
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: prev.bottom
margin-left: 500
@onSetup: |
if not(g_game.getFeature(GameEnterGameShowAppearance)) then
self:hide()

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
EnterGameWindow < MainWindow
!text: tr('Enter Game')
size: 236 298
size: 236 316
draggable: false
EnterGameButton < Button
@ -183,6 +183,16 @@ EnterGameWindow
anchors.top: prev.bottom
margin-top: 2
CheckBox
id: httpLoginBox
enabled: true
!text: tr('Enable HTTP login')
!tooltip: tr('If login fails using HTTPS (encrypted) try with HTTP (unencrypted)')
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-top: 2
HorizontalSeparator
anchors.left: parent.left
anchors.right: parent.right
@ -203,4 +213,4 @@ EnterGameWindow
anchors.left: parent.left
margin-top: 5
color: green
text-auto-resize: true
text-auto-resize: true

View file

@ -18,7 +18,7 @@ function AddServer.add()
local port = addServerWindow:getChildById('port'):getText()
local protocol = addServerWindow:getChildById('protocol'):getCurrentOption().text
local added, error = ServerList.add(host, port, protocol)
local added, error = ServerList.add(host, port, protocol, false)
if not added then
displayErrorBox(tr('Error'), tr(error))
else

View file

@ -29,7 +29,7 @@ end
function ServerList.load()
for host, server in pairs(servers) do
ServerList.add(host, server.port, server.protocol, true)
ServerList.add(host, server.port, server.protocol, httpLogin, true)
end
end
@ -41,18 +41,21 @@ function ServerList.select()
EnterGame.setDefaultServer(selected:getId(), server.port, server.protocol)
EnterGame.setAccountName(server.account)
EnterGame.setPassword(server.password)
EnterGame.setHttpLogin(server.httpLogin)
ServerList.hide()
end
end
end
function ServerList.add(host, port, protocol, load)
function ServerList.add(host, port, protocol, httpLogin, load)
if not host or not port or not protocol then
return false, 'Failed to load settings'
elseif not load and servers[host] then
return false, 'Server already exists'
elseif host == '' or port == '' then
return false, 'Required fields are missing'
elseif httpLogin == nil then
httpLogin = false
end
local widget = g_ui.createWidget('ServerWidget', serverTextList)
widget:setId(host)
@ -62,7 +65,8 @@ function ServerList.add(host, port, protocol, load)
port = port,
protocol = protocol,
account = '',
password = ''
password = '',
httpLogin = httpLogin
}
end

View file

@ -181,7 +181,8 @@ function HTTP.onPost(operationId, url, err, data)
err = err .. " (" .. data:sub(1, 100) .. ")"
end
end
data = result
-- data = result
end
if operation.callback then
operation.callback(data, err)
@ -308,3 +309,4 @@ connect(g_http,
g_http.setUserAgent(HTTP.agent)
g_http.setEnableTimeOutOnReadWrite(HTTP.enableTimeOut)

View file

@ -119,26 +119,26 @@ endif()
# === ASAN ===
if(ASAN_ENABLED)
log_option_enabled("asan")
log_option_enabled("asan")
if(MSVC)
if(MSVC)
target_compile_options(${PROJECT_NAME} PUBLIC /fsanitize=address)
else()
else()
target_compile_options(${PROJECT_NAME} PUBLIC -fsanitize=address)
target_link_options(${PROJECT_NAME} PUBLIC -fsanitize=address)
endif()
endif()
else()
log_option_disabled("asan")
log_option_disabled("asan")
endif()
# === DEBUG LOG ===
# cmake -DDEBUG_LOG=ON ..
if(CMAKE_BUILD_TYPE MATCHES Debug)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DDEBUG_LOG=ON )
log_option_enabled("DEBUG LOG")
else()
log_option_disabled("DEBUG LOG")
target_compile_definitions(${PROJECT_NAME} PRIVATE -DDEBUG_LOG=ON )
log_option_enabled("DEBUG LOG")
else()
log_option_disabled("DEBUG LOG")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
# *****************************************************************************
@ -194,6 +194,8 @@ find_package(asio REQUIRED)
find_package(Threads REQUIRED)
find_package(STDUUID CONFIG REQUIRED)
find_package(pugixml CONFIG REQUIRED)
find_package(ZLIB REQUIRED)
find_package(httplib CONFIG REQUIRED)
if(APPLE)
# Required for Physfs
find_library(FOUNDATION Foundation REQUIRED)
@ -264,6 +266,7 @@ set(SOURCE_FILES
framework/net/outputmessage.cpp
framework/net/protocol.cpp
framework/net/protocolhttp.cpp
framework/net/httplogin.cpp
framework/net/server.cpp
framework/otml/otmldocument.cpp
framework/otml/otmlemitter.cpp
@ -415,6 +418,13 @@ target_sources(${PROJECT_NAME} PRIVATE ${SOURCE_FILES})
# *****************************************************************************
if(MSVC)
# Set variables to have Windows Vista Value so httplib will build 'inet_pton'
target_compile_definitions(${PROJECT_NAME}
PRIVATE
NTDDI_VERSION=0x06000000
_WIN32_WINNT=0x0600
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
@ -526,11 +536,11 @@ else() # Linux
${CMAKE_THREAD_LIBS_INIT}
${Protobuf_INCLUDE_DIRS}
${GMP_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
${PHYSFS_INCLUDE_DIR}
${GLEW_INCLUDE_DIR}
${PARALLEL_HASHMAP_INCLUDE_DIRS}
${NLOHMANN_JSON_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
@ -545,10 +555,12 @@ else() # Linux
${DirectX_LIBRARIES}
${OGG_LIBRARY}
${GMP_LIBRARY}
${OPENSSL_LIBRARIES}
${STDUUID}
${FOUNDATION}
${IOKIT}
${OPENSSL_LIBRARY}
${OPENSSL_CRYPTO_LIBRARY}
${HTTPLIB_LIBRARY}
Threads::Threads
X11::X11
@ -558,6 +570,10 @@ else() # Linux
Vorbis::vorbisfile
LibLZMA::LibLZMA
pugixml::pugixml
ZLIB::ZLIB
OpenSSL::SSL
OpenSSL::Crypto
httplib::httplib
)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")

View file

@ -55,6 +55,7 @@
#ifdef FRAMEWORK_NET
#include <framework/net/protocol.h>
#include <framework/net/protocolhttp.h>
#include <framework/net/httplogin.h>
#include <framework/net/server.h>
#endif
@ -182,6 +183,12 @@ void Application::registerLuaFunctions()
g_lua.bindSingletonFunction("g_logger", "setLevel", &Logger::setLevel, &g_logger);
g_lua.bindSingletonFunction("g_logger", "getLevel", &Logger::getLevel, &g_logger);
// Login Http
g_lua.registerClass<LoginHttp>();
g_lua.bindClassStaticFunction<LoginHttp>("create", [] { return std::make_shared<LoginHttp>(); });
g_lua.bindClassMemberFunction<LoginHttp>("httpLogin", &LoginHttp::httpLogin);
// Http
g_lua.registerSingletonClass("g_http");
g_lua.bindSingletonFunction("g_http", "setUserAgent", &Http::setUserAgent, &g_http);
g_lua.bindSingletonFunction("g_http", "setEnableTimeOutOnReadWrite", &Http::setEnableTimeOutOnReadWrite, &g_http);

View file

@ -0,0 +1,223 @@
/*
* Copyright (c) 2010-2022 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "httplogin.h"
#include <framework/core/asyncdispatcher.h>
#include <framework/core/eventdispatcher.h>
#include <future>
#include <httplib.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
using json = nlohmann::json;
LoginHttp::LoginHttp() {
this->characters.clear();
this->worlds.clear();
this->session.clear();
}
void LoginHttp::Logger(const auto &req, const auto &res) {
std::cout << "======= LOG ======= " << std::endl;
std::cout << "-- REQUEST --" << std::endl;
std::cout << req.method << std::endl;
std::cout << req.path << std::endl;
std::cout << req.body << std::endl;
for (auto itr = req.headers.begin(); itr != req.headers.end(); ++itr) {
std::cout << itr->first << '\t' << itr->second << '\n';
}
std::cout << "-- RESPONSE --" << std::endl;
std::cout << res.version << std::endl;
std::cout << res.status << std::endl;
std::cout << res.reason << std::endl;
std::cout << res.body << std::endl;
std::cout << res.location << std::endl;
for (auto itr = res.headers.begin(); itr != res.headers.end(); ++itr) {
std::cout << itr->first << '\t' << itr->second << '\n';
}
std::cout << "========= " << std::endl;
}
void LoginHttp::startHttpLogin(const std::string &host, const std::string &path,
uint16_t port, const std::string &email,
const std::string &password) {
httplib::SSLClient cli(host, port);
cli.set_logger(
[&](const auto &req, const auto &res) { LoginHttp::Logger(req, res); });
json body = json{{"email", email}, {"password", password}, {"type", "login"}};
if (auto res = cli.Post(path, body.dump(1), "application/json")) {
if (res->status == 200) {
json bodyResponse = json::parse(res->body);
std::cout << bodyResponse.dump(4) << std::endl;
std::cout << std::boolalpha << json::accept(res->body) << std::endl;
}
} else {
auto err = res.error();
std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
}
}
std::string LoginHttp::getCharacterList() { return this->characters; }
std::string LoginHttp::getWorldList() { return this->worlds; }
std::string LoginHttp::getSession() { return this->session; }
void LoginHttp::httpLogin(const std::string &host, const std::string &path,
uint16_t port, const std::string &email,
const std::string &password, int request_id,
bool httpLogin) {
g_asyncDispatcher.dispatch(
[this, host, path, port, email, password, request_id, httpLogin] {
httplib::Result result =
this->loginHttpsJson(host, path, port, email, password);
if (httpLogin && (!result || result->status != Success)) {
result = loginHttpJson(host, path, port, email, password);
}
if (result && result->status == Success) {
g_dispatcher.addEvent([this, request_id] {
g_lua.callGlobalField("EnterGame", "loginSuccess", request_id,
this->getSession(), this->getWorldList(),
this->getCharacterList());
});
} else {
int status = 0;
std::string msg = "";
if (result) {
status = result->status;
msg = httplib::to_string(result.error());
} else {
status = -1;
msg = "Unknown error";
}
g_dispatcher.addEvent([this, request_id, status, msg] {
g_lua.callGlobalField("EnterGame", "loginFailed", request_id, msg,
status);
});
}
});
}
httplib::Result LoginHttp::loginHttpsJson(const std::string &host,
const std::string &path,
uint16_t port,
const std::string &email,
const std::string &password) {
httplib::SSLClient client(host, port);
client.set_logger(
[&](const auto &req, const auto &res) { LoginHttp::Logger(req, res); });
json body = {{"email", email}, {"password", password}, {"type", "login"}};
httplib::Result response =
client.Post(path, body.dump(1), "application/json");
if (!response) {
std::cout << "HTTPS error: unknown" << std::endl;
} else if (response->status != Success) {
std::cout << "HTTPS error: " << httplib::to_string(response.error())
<< std::endl;
} else {
std::cout << "HTTPS status: " << httplib::to_string(response.error())
<< std::endl;
}
if (response && response->status == Success &&
!parseJsonResponse(response->body)) {
response->status = -1;
}
return response;
}
httplib::Result LoginHttp::loginHttpJson(const std::string &host,
const std::string &path,
uint16_t port,
const std::string &email,
const std::string &password) {
httplib::Client client(host, port);
client.set_logger(
[&](const auto &req, const auto &res) { LoginHttp::Logger(req, res); });
json body = {{"email", email}, {"password", password}, {"type", "login"}};
httplib::Result response =
client.Post(path, body.dump(1), "application/json");
if (!response) {
std::cout << "HTTP error: unknown" << std::endl;
} else if (response->status != Success) {
std::cout << "HTTP error: " << httplib::to_string(response.error())
<< std::endl;
} else {
std::cout << "HTTP status: " << httplib::to_string(response.error())
<< std::endl;
}
if (response && response->status == Success &&
!parseJsonResponse(response->body)) {
response->status = -1;
}
return response;
}
bool LoginHttp::parseJsonResponse(const std::string &body) {
json responseJson = json::parse(body);
if (!responseJson.contains("session")) {
return false;
}
if (responseJson.contains("playdata")) {
json playdata = responseJson.at("playdata");
this->characters = "{}";
if (playdata.contains("characters")) {
this->characters = to_string(playdata.at("characters"));
}
this->worlds = "{}";
if (playdata.contains("worlds")) {
this->worlds = to_string(playdata.at("worlds"));
}
}
this->session = to_string(responseJson.at("session"));
return true;
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2022 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <framework/luaengine/luaobject.h>
class LoginHttp : public LuaObject {
public:
LoginHttp();
void startHttpLogin(const std::string &host, const std::string &path,
uint16_t port, const std::string &email,
const std::string &password);
void Logger(const auto &req, const auto &res);
std::string getCharacterList();
std::string getWorldList();
std::string getSession();
bool parseJsonResponse(const std::string &body);
void httpLogin(const std::string &host, const std::string &path,
uint16_t port, const std::string &email,
const std::string &password, int request_id, bool httpLogin);
httplib::Result loginHttpsJson(const std::string &host,
const std::string &path, uint16_t port,
const std::string &email,
const std::string &password);
httplib::Result loginHttpJson(const std::string &host,
const std::string &path, uint16_t port,
const std::string &email,
const std::string &password);
enum Result : int { Success = 200, Error = -1 };
private:
std::string characters;
std::string worlds;
std::string session;
};

View file

@ -559,6 +559,19 @@ void WebsocketSession::start()
});
}
void WebsocketSession::on_resolve(const std::error_code& ec, asio::ip::tcp::resolver::iterator iterator)
{
if (ec) {
@ -976,4 +989,4 @@ void WebsocketSession::close()
}
}
}
}
}

View file

@ -22,7 +22,7 @@
#pragma once
// common C headers
// common C headers
#include <cassert>
#include <cmath>
#include <cstddef>

View file

@ -3,29 +3,31 @@
#include "uri.h"
ParsedURI parseURI(const std::string& url)
{
const auto& value_default = [](const std::string& value, std::string&& deflt) -> std::string {
return (value.empty() ? deflt : value);
};
ParsedURI parseURI(const std::string &url) {
// Regular expression pattern to match URL components
static const std::regex PARSE_URL{
R"((([httpsw]{2,5})://)?([^/ :]+)(:(\d+))?(/(.+)?))",
std::regex_constants::ECMAScript | std::regex_constants::icase};
const auto& value_to_lower = [](std::string data) -> std::string {
for (char& c : data)
c = tolower(c);
return data;
};
ParsedURI result;
std::smatch match;
// Check if the URL matches the pattern and has the correct number of components
if (std::regex_match(url, match, PARSE_URL) && match.size() == 8) {
// Set protocol with default value "http" if not provided
result.protocol = (match[2].str().empty()) ? "http" : match[2].str();
// Set domain
result.domain = match[3].str();
// Check if protocol is "https" or "wss" to determine default port
const bool isHttps = (result.protocol == "https" || result.protocol == "wss");
result.port = (match[5].str().empty()) ? (isHttps) ? "443" : "80" : match[5].str();
// Set query with default value "/"
result.query = (match[6].str().empty()) ? "/" : match[6].str();
}
return result;
}
// Note: only "http", "https", "ws", and "wss" protocols are supported
static const std::regex PARSE_URL{ R"((([httpsw]{2,5})://)?([^/ :]+)(:(\d+))?(/(.+)?))",
std::regex_constants::ECMAScript | std::regex_constants::icase };
ParsedURI result;
std::smatch match;
if (std::regex_match(url, match, PARSE_URL) && match.size() == 8) {
result.protocol = value_default(value_to_lower(std::string(match[2])), "http");
result.domain = match[3];
const bool is_sequre_protocol = (result.protocol == "https" || result.protocol == "wss");
result.port = value_default(match[5], (is_sequre_protocol) ? "443" : "80");
result.query = value_default(match[6], "/");
}
return result;
}

View file

@ -13,7 +13,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3021002 < PROTOBUF_MIN_PROTOC_VERSION
#if 3021012 < PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -309,6 +309,7 @@ cmd /c "start ../vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\tools\protobuf\
</ClCompile>
<ClCompile Include="..\src\framework\luafunctions.cpp" />
<ClCompile Include="..\src\framework\net\connection.cpp" />
<ClCompile Include="..\src\framework\net\httplogin.cpp" />
<ClCompile Include="..\src\framework\net\inputmessage.cpp" />
<ClCompile Include="..\src\framework\net\outputmessage.cpp" />
<ClCompile Include="..\src\framework\net\protocol.cpp" />
@ -468,6 +469,7 @@ cmd /c "start ../vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\tools\protobuf\
<ClInclude Include="..\src\framework\luaengine\luavaluecasts.h" />
<ClInclude Include="..\src\framework\net\connection.h" />
<ClInclude Include="..\src\framework\net\declarations.h" />
<ClInclude Include="..\src\framework\net\httplogin.h" />
<ClInclude Include="..\src\framework\net\inputmessage.h" />
<ClInclude Include="..\src\framework\net\outputmessage.h" />
<ClInclude Include="..\src\framework\net\protocol.h" />

View file

@ -554,6 +554,8 @@
</ClCompile>
<ClCompile Include="..\src\framework\ui\uiqrcode.cpp">
<Filter>Source Files\framework\ui</Filter>
<ClCompile Include="..\src\framework\net\httplogin.cpp">
<Filter>Source Files\framework\net</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -1075,6 +1077,8 @@
</ClInclude>
<ClInclude Include="..\src\framework\ui\uiqrcode.h">
<Filter>Header Files\framework\ui</Filter>
<ClInclude Include="..\src\framework\net\httplogin.h">
<Filter>Header Files\framework\net</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
@ -1082,4 +1086,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>

View file

@ -5,7 +5,8 @@
<PREPROCESSOR_DEFS>
WIN32;
_CRT_SECURE_NO_WARNINGS;
_WIN32_WINNT=0x0501;
_WIN32_WINNT=0x0600;
NTDDI_VERSION=0x06000000;
BOT_PROTECTION;
CRASH_HANDLER;
FRAMEWORK_GRAPHICS;

View file

@ -3,19 +3,20 @@
"version-string": "1.0.0",
"dependencies": [
"asio",
"cpp-httplib",
"discord-rpc",
"liblzma",
"libogg",
"libvorbis",
"nlohmann-json",
"openal-soft",
"openssl",
"parallel-hashmap",
"physfs",
"protobuf",
"zlib",
"liblzma",
"parallel-hashmap",
"stduuid",
"discord-rpc",
"pugixml",
"stduuid",
"zlib",
{
"name": "luajit",
"platform": "!android"