Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[kRO] support (main, sakray, zero) #3430

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
68af398
Update servers.txt
alisonrag May 8, 2021
bf05c93
[kRO-Zero] 2021-05-08 tables update
alisonrag May 8, 2021
95f4e2b
[kRO-Sakray] 2021-05-08 tables update
alisonrag May 8, 2021
9c1012f
[kRO-Main] 2021-05-08 tables update
alisonrag May 8, 2021
8f63b08
remove old kRO files
alisonrag May 8, 2021
d356880
[kRO-Zero] 2021-05-08 network update
alisonrag May 8, 2021
1a705eb
[kRO-Sakray] 2021-05-08 network update
alisonrag May 8, 2021
f76b1ac
[kRO-Main] 2021-05-08 Network update
alisonrag May 8, 2021
839bbf4
remove secureLogin
ya4ept May 9, 2021
9791383
Merge branch 'master' into kRO-support
alisonrag May 13, 2021
41beb0d
Merge branch 'master' into kRO-support
alisonrag Jul 13, 2021
17063c8
[kRO] Add plugin to login (kRO_auth)
alisonrag Jul 13, 2021
02f5d29
[kRO] update map_login
alisonrag Jul 13, 2021
6501bab
[kRO] add missing import
alisonrag Jul 13, 2021
6e3754a
revert map_login in kRO Sakray
alisonrag Jul 14, 2021
c1cf2d4
fix: update the login form parse
alisonrag Aug 5, 2022
6f9db6f
Merge branch 'master' into kRO-support
alisonrag Aug 5, 2022
654c4bf
Merge branch 'master' into kRO-support
alisonrag Aug 12, 2022
5baae34
Merge branch 'master' into kRO-support
alisonrag Aug 17, 2022
7f4cf59
fix: update sakray network send file
alisonrag Aug 18, 2022
1ad6861
Merge branch 'master' into kRO-support
ya4ept Aug 18, 2022
2d37723
fix: add new 0x0add unpack string
alisonrag Aug 19, 2022
3301e91
Merge branch 'master' into kRO-support
alisonrag Aug 20, 2022
b657259
Merge branch 'master' into kRO-support
alisonrag Aug 21, 2022
077b9f8
Merge branch 'master' into kRO-support
alisonrag Jan 2, 2023
24745cd
Merge branch 'master' into kRO-support
alisonrag Apr 14, 2023
29f6245
feat: implement motp login
alisonrag Apr 14, 2023
c1f56ba
Merge branch 'master' into kRO-support
alisonrag Aug 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions plugins/kRO_auth/kRO_auth.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# by alisonrag v1.0 (2021-07-12)
# this plugin allows you to get token for authorization on kRO
package kRO_auth;

use strict;
use warnings;

use lib 'C:/Strawberry/perl/lib/';
use lib 'C:/Strawberry/perl/site/lib';
use lib 'C:/Strawberry/perl/vendor/lib';

use LWP::UserAgent;
use HTTP::Cookies;
use HTTP::Headers;
use HTML::Form;
use HTTP::Request::Common qw(POST GET);

use Globals qw(%config $masterServer);
use Log qw(debug message);
use Misc qw(configModify);
use Plugins;

Plugins::register('kRO_auth', 'korea RO SSO Authenticator', \&unload);

my $hooks = Plugins::addHooks(
['initialized', \&setGlobalVars],
['Network::serverConnect/master', \&getToken]
);

my %request;

sub unload {
message "[kRO_auth] plugin unloading, ", "system";
undef %request;
Plugins::delHooks($hooks);
}

sub setGlobalVars {
$request{'url_host'} = 'login.gnjoy.com';
$request{'url_login'} = 'https://login.gnjoy.com/proc/loginproc.asp';
$request{'url_game_start'} = 'https://login.gnjoy.com/webstarter/index.asp?callback=myCallback&gamecode=%s&_=%s';
$request{'user_agent'} = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36';

if ( $masterServer->{serverType} eq 'Zero' ) {
$request{'game_code'} = '0036';
$request{'url'} = 'http://roz.gnjoy.com';
$request{'url_index'} = 'http://roz.gnjoy.com/index.asp';
$request{'url_referer'} = 'https://roz.gnjoy.com/';
} elsif ( $masterServer->{serverType} eq 'kRO' ) {
$request{'game_code'} = '0011';
$request{'url'} = 'http://ro.gnjoy.com';
$request{'url_index'} = 'http://ro.gnjoy.com/index.asp';
$request{'url_referer'} = 'https://ro.gnjoy.com/';
} elsif ( $masterServer->{serverType} eq 'Sakray' ) {
$request{'game_code'} = '2011';
$request{'url'} = 'http://ro.gnjoy.com';
$request{'url_index'} = 'http://ro.gnjoy.com/index.asp';
$request{'url_referer'} = 'https://ro.gnjoy.com/';
} else {
unload();
}
}

sub getToken {
# start necessary variables
my ($ua, $response, @forms, $input, $headers, $url, $req, $cookie_jar);

message "[kRO_auth] Trying to Authenticate...\n", "system";
debug "[kRO_auth] Setting Up the LWP AGENT...\n";
# set lwp and http values
$cookie_jar = HTTP::Cookies->new(autosave => 1);
$ua = LWP::UserAgent->new(agent => $request{'user_agent'}, cookie_jar => $cookie_jar);
$ua->agent($request{'user_agent'});

# first request to index.php
debug "[kRO_auth] First Request: ".$request{'url'}."\n";
$req = GET $request{'url_index'};
$response = $ua->request($req);

if (!$response->is_success) {
die "[kRO_auth] Error in First Request. Status: " . $response->status_line . "\n";
}

debug "[kRO_auth] Setting Up the Login Request...\n";
$cookie_jar->extract_cookies($response);
@forms = HTML::Form->parse($response, $response->base);
$input = $forms[1]->find_input('__GnjoyRequestVerificationToken');

# set LWP User Agent and Header to login
$ua->cookie_jar($cookie_jar);
$headers = HTTP::Headers->new(
'Pragma' => 'no-cache',
'Origin' => $request{'url'},
'Accept-Encoding' => 'gzip, deflate, br',
'Host' => $request{'url_host'},
'Accept-Language' => 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'Upgrade-Insecure-Requests' => '1',
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Cache-Control' => 'no-cache',
'Referer' => $request{'url_index'},
'Connection' => 'keep-alive'
);
$ua->default_headers($headers);

debug "[kRO_auth] Trying to Login: " . $request{'url_login'} . "\n";
# try to login
$url = $request{'url_login'};
$req = POST $url, [
__GnjoyRequestVerificationToken => $input->{value},
cpflag => 'G',
loginsubmit => 'N',
svc => 'G000',
uid => $config{username},
upass => $config{password},
rtnurl => $request{'url_index'}
];

$response = $ua->request($req);
if (!$response->is_success) {
die "[kRO_auth] Error in Login Request. Status: " . $response->status_line . "\n";
}

debug "[kRO_auth] Setting Up the Game Start Request...\n";
$cookie_jar->extract_cookies($response);
$ua->cookie_jar($cookie_jar);
# set Header and try to emulate Game Execute
$headers = HTTP::Headers->new(
'authority' => $request{'url_host'},
'user-agent' => $request{'user_agent'},
'dnt' => '1',
'accept' => '*/*',
'sec-fetch-site' => 'same-site',
'sec-fetch-mode' => 'no-cors',
'sec-fetch-dest' => 'script',
'referer' => $request{'url_referer'},
'accept-language' => 'en-US,en;q=0.9,ar-MA;q=0.8,ar;q=0.7,fr;q=0.6',
'Pragma' => 'no-cache',
'Origin' => $request{'url'},
'Host' => $request{'url_host'},
'Upgrade-Insecure-Requests' => '1',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
);
$ua->default_headers($headers);

$url = sprintf($request{'url_game_start'}, $request{'game_code'}, time());
debug "[kRO_auth] Trying to Get the Token: ".$url."\n";
$req = GET $url;
$response = $ua->request($req);

if (!$response->is_success) {
die "[kRO_auth] Error in Get the Token. Status: " . $response->status_line . "\n";
}

if( $response->decoded_content =~/rouri\-kor\:([aA-zZ0-9]+)\&/ || $response->decoded_content =~/rouri\-kor\-zero\:([aA-zZ0-9]+)\&/ || $response->decoded_content =~/rouri\-kor\-sakray\:([aA-zZ0-9]+)\&/ ) {
debug "[kRO_auth] Token: $1 \n";
configModify ('accessToken', $1, 1);
message "[kRO_auth] Successfully Authenticated...\n", "system";
} else {
die "[kRO_auth] Error in parse Token. \nContent:\n" . $response->decoded_content . "\n";
}
}

1;
3 changes: 2 additions & 1 deletion src/Globals.pm
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ our %EXPORT_TAGS = (
state => [qw($accountID $cardMergeIndex @cardMergeItemsID $charID @chars @chars_old @friendsID %friends %incomingFriend $field %homunculus $itemsList @itemsID %items $monstersList @monstersID %monsters @npcsID %npcs $npcsList @playersID %players @portalsID @portalsID_old %portals %portals_old $portalsList $storeList $currentChatRoom @currentChatRoomUsers @chatRoomsID %createdChatRoom %chatRooms @skillsID $storageTitle @arrowCraftID %guild %incomingGuild @spellsID %spells @unknownPlayers @unknownNPCs $useArrowCraft %currentDeal %incomingDeal %outgoingDeal @identifyID @partyUsersID %incomingParty @petsID %pets $venderItemList $venderID $venderCID @venderListsID $buyerItemList $buyerPriceLimit @selfBuyerItemList $buyerID $buyingStoreID @buyerListsID @articles $articles %venderLists %buyerLists %monsters_old @monstersID_old %npcs_old %items_old %players_old @playersID_old @servers $sessionID $sessionID2 $accountSex $accountSex2 $map_ip $map_port $KoreStartTime $secureLoginKey $initSync $lastConfChangeTime $petsList $playersList $portalsList %elementals $elementalsList @elementalsID @playerNameCacheIDs %playerNameCache %pet $pvp $cashList $slavesList @slavesID %slaves %cashShop $skillExchangeItem $refineUI %clan %universalCatalog $mergeItemList)],
network => [qw($remote_socket $net $messageSender $charServer $conState $conState_tries $encryptVal $ipc $bus $masterServer $lastSwitch $packetParser $clientPacketHandler $bytesSent $incomingMessages $outgoingClientMessages $enc_val1 $enc_val2 $captcha_state $captcha_image $captcha_image_content $captcha_key $captcha_size)],
interface => [qw($interface)],
misc => [qw($quit $reconnectCount @lastpm %lastpm @privMsgUsers %timeout_ex $shopstarted $buyershopstarted $bankingopened $dmgpsec $totalelasped $elasped $totaldmg %overallAuth %responseVars %talk $startTime_EXP $startingzeny @monsters_Killed $bExpSwitch $jExpSwitch $totalBaseExp $totalJobExp $shopEarned %itemChange $XKore_dontRedirect $monkilltime $monstarttime $startedattack $firstLoginMap $sentWelcomeMessage $versionSearch $monsterBaseExp $monsterJobExp %flags %damageTaken $logAppend @sellList $userSeed $taskManager $repairList $mailList $rodexList $rodexWrite $rodexCurrentType $auctionList $questList %achievements $achievementList $hotkeyList $devotionList $cookingList $currentCookingType $makableList %charSvrSet @deadTime $refineList $current_item_list $ignored_all %roulette $in_market @reputation_list_name @reputation_list)],
misc => [qw($quit $reconnectCount @lastpm %lastpm @privMsgUsers %timeout_ex $waiting_for_motp $shopstarted $buyershopstarted $bankingopened $dmgpsec $totalelasped $elasped $totaldmg %overallAuth %responseVars %talk $startTime_EXP $startingzeny @monsters_Killed $bExpSwitch $jExpSwitch $totalBaseExp $totalJobExp $shopEarned %itemChange $XKore_dontRedirect $monkilltime $monstarttime $startedattack $firstLoginMap $sentWelcomeMessage $versionSearch $monsterBaseExp $monsterJobExp %flags %damageTaken $logAppend @sellList $userSeed $taskManager $repairList $mailList $rodexList $rodexWrite $rodexCurrentType $auctionList $questList %achievements $achievementList $hotkeyList $devotionList $cookingList $currentCookingType $makableList %charSvrSet @deadTime $refineList $current_item_list $ignored_all %roulette $in_market @reputation_list_name @reputation_list)],
syncs => [qw($syncSync $syncMapSync)],
cmdqueue => [qw($cmdQueue @cmdQueueList $cmdQueueStartTime $cmdQueueTime @cmdQueuePriority)],
);
Expand Down Expand Up @@ -541,6 +541,7 @@ our @lastpm;
our %lastpm;
our @privMsgUsers;
our %timeout_ex;
our $waiting_for_motp;
our %overallAuth;
our $shopstarted;
our $bankingopened;
Expand Down
5 changes: 4 additions & 1 deletion src/Network/DirectConnection.pm
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,10 @@ sub checkConnection {
undef $secureLoginKey;

} elsif (timeOut($timeout{'master'}) && timeOut($timeout_ex{'master'})) {
if ($config{dcOnMaxReconnections} && $config{dcOnMaxReconnections} <= $reconnectCount) {
if ($waiting_for_motp) {
$timeout_ex{'master'}{'time'} = time;
return;
} elsif ($config{dcOnMaxReconnections} && $config{dcOnMaxReconnections} <= $reconnectCount) {
error T("Auto disconnecting on MaxReconnections!\n");
chatLog("k", T("*** Exceeded the maximum number attempts to reconnect, auto disconnect! ***\n"));
$quit = 1;
Expand Down
39 changes: 36 additions & 3 deletions src/Network/Receive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8032,9 +8032,42 @@ sub received_login_token {
my ($self, $args) = @_;
# XKore mode 1 / 3.
return if ($self->{net}->version == 1);
my $master = $masterServers{$config{master}};
# rathena use 0064 not 0825
$messageSender->sendTokenToServer($config{username}, $config{password}, $master->{master_version}, $master->{version}, $args->{login_token}, $args->{len}, $master->{OTP_ip}, $master->{OTP_port});

$timeout_ex{'master'}{'time'} = time;
$timeout{'master'}{'time'} = time;
$waiting_for_motp = 0;

if($args->{login_type} == 0) {
my $master = $masterServers{$config{master}};
# rathena use 0064 not 0825
$messageSender->sendTokenToServer($config{username}, $config{password}, $master->{master_version}, $master->{version}, $args->{login_token}, $args->{len}, $master->{OTP_ip}, $master->{OTP_port});
} elsif($args->{login_type} == 400) {
$waiting_for_motp = 1;
my $code = $interface->query(T("Please enter the MOTP code."));
$messageSender->sendMotpToServer($code);
$timeout_ex{'master'}{'time'} = time;
$timeout{'master'}{'time'} = time;
} elsif($args->{login_type} == 500) {
error TF("Wrong MOTP for account [%s]\n", $config{'username'}), "connection";
$timeout_ex{master}{time} = 0;
$conState_tries = 0;
} elsif($args->{login_type} == 600) {
error TF("Password Error for account [%s]\n", $config{'username'}), "connection";
Plugins::callHook('invalid_password');
if (!$net->clientAlive() && !$config{'ignoreInvalidLogin'} && !UNIVERSAL::isa($net, 'Network::XKoreProxy')) {
my $password = $interface->query(T("Enter your Ragnarok Online password again."), isPassword => 1);
if (defined($password)) {
configModify('password', $password, 1);
$timeout_ex{master}{time} = 0;
$conState_tries = 0;
} else {
quit();
return;
}
}
} else {
error TF("Unknown MOTP login_type [%s]\n", $args->{login_type}), "connection";
}
}

# this info will be sent to xkore 2 clients
Expand Down
16 changes: 15 additions & 1 deletion src/Network/Receive/Sakray.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,22 @@
# See http://www.gnu.org/licenses/gpl.html for the full license.
########################################################################
# by alisonrag / thanks to Asheraf

package Network::Receive::Sakray;

use strict;
use base qw(Network::Receive::ServerType0);
use Globals;

sub new {
my ($class) = @_;
my $self = $class->SUPER::new(@_);

my %packets = (
'0ADD' => ['item_appeared', 'a4 V v C v2 C2 v C v', [qw(ID nameID type identified x y subx suby amount show_effect effect_type )]],
);

$self->{packet_list}{$_} = $packets{$_} for keys %packets;

my %handlers = qw(
received_characters 099D
received_characters_info 082D
Expand All @@ -45,6 +52,13 @@ sub new {

$self->{packet_lut}{$_} = $handlers{$_} for keys %handlers;

$self->{vender_items_list_item_pack} = 'V v2 C V C3 a16 a25';
$self->{npc_store_info_pack} = "V V C V";
$self->{buying_store_items_list_pack} = "V v C V";
$self->{makable_item_list_pack} = "V4";
$self->{rodex_read_mail_item_pack} = "v V C3 a16 a4 C a4 a25";
$self->{npc_market_info_pack} = "V C V2 v";

return $self;
}

Expand Down
41 changes: 15 additions & 26 deletions src/Network/Receive/Zero.pm
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@
########################################################################
# Korea (kRO) # by alisonrag / sctnightcore
# The majority of private servers use eAthena, this is a clone of kRO

package Network::Receive::Zero;

use strict;
use base qw(Network::Receive::ServerType0);
use Log qw(debug);
use Globals;
use Translation;
use I18N qw(bytesToString);
use Utils::DataStructures;

sub new {
my ($class) = @_;
my $self = $class->SUPER::new(@_);

my %packets = (
'0ADD' => ['item_appeared', 'a4 V v C v2 C2 v C v', [qw(ID nameID type identified x y subx suby amount show_effect effect_type )]],
);

$self->{packet_list}{$_} = $packets{$_} for keys %packets;

my %handlers = qw(
received_characters 099D
received_characters_info 082D
Expand All @@ -50,28 +53,14 @@ sub new {

$self->{packet_lut}{$_} = $handlers{$_} for keys %handlers;

return $self;
}

sub party_users_info {
my ($self, $args) = @_;
return unless Network::Receive::changeToInGameState();

$char->{party}{name} = bytesToString($args->{party_name});
$self->{vender_items_list_item_pack} = 'V v2 C V C3 a16 a25';
$self->{npc_store_info_pack} = "V V C V";
$self->{buying_store_items_list_pack} = "V v C V";
$self->{makable_item_list_pack} = "V4";
$self->{rodex_read_mail_item_pack} = "v V C3 a16 a4 C a4 a25";
$self->{npc_market_info_pack} = "V C V2 v";

for (my $i = 0; $i < length($args->{playerInfo}); $i += 54) {
my $ID = substr($args->{playerInfo}, $i, 4);
if (binFind(\@partyUsersID, $ID) eq "") {
binAdd(\@partyUsersID, $ID);
}
$char->{party}{users}{$ID} = new Actor::Party();
@{$char->{party}{users}{$ID}}{qw(ID GID name map admin online jobID lv)} = unpack('V V Z24 Z16 C2 v2', substr($args->{playerInfo}, $i, 54));
$char->{party}{users}{$ID}{name} = bytesToString($char->{party}{users}{$ID}{name});
$char->{party}{users}{$ID}{admin} = !$char->{party}{users}{$ID}{admin};
$char->{party}{users}{$ID}{online} = !$char->{party}{users}{$ID}{online};

debug TF("Party Member: %s (%s)\n", $char->{party}{users}{$ID}{name}, $char->{party}{users}{$ID}{map}), "party", 1;
}
return $self;
}

1;
38 changes: 35 additions & 3 deletions src/Network/Receive/kRO.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,43 @@
# $Id: kRO.pm 6687 2009-04-19 19:04:25Z technologyguild $
########################################################################
# Korea (kRO)
# The majority of private servers use eAthena, this is a clone of kRO

package Network::Receive::kRO;

use strict;
use Network::Receive qw(:actor_type :connection :stat_info :party_invite :party_leave :exp_origin);
use base 'Network::Receive';
use base qw(Network::Receive::ServerType0);

sub new {
my ($class) = @_;
my $self = $class->SUPER::new(@_);

my %packets = (
'0ADD' => ['item_appeared', 'a4 V v C v2 C2 v C v', [qw(ID nameID type identified x y subx suby amount show_effect effect_type )]],
);

$self->{packet_list}{$_} = $packets{$_} for keys %packets;

my %handlers = qw(
received_characters 099D
received_characters_info 082D
sync_received_characters 09A0
account_server_info 0AC4
received_character_ID_and_Map 0AC5
map_changed 0AC7
account_id 0283
item_appeared 0ADD
);

$self->{packet_lut}{$_} = $handlers{$_} for keys %handlers;

$self->{vender_items_list_item_pack} = 'V v2 C V C3 a16 a25';
$self->{npc_store_info_pack} = "V V C V";
$self->{buying_store_items_list_pack} = "V v C V";
$self->{makable_item_list_pack} = "V4";
$self->{rodex_read_mail_item_pack} = "v V C3 a16 a4 C a4 a25";
$self->{npc_market_info_pack} = "V C V2 v";

return $self;
}

1;
Loading
Loading