暗号式予約販売タイトルの修理ロジックを追加

タイトルタグの設定のテストは現状失敗するので無効化

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@842 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2015-03-19 02:49:26 +00:00
parent c50f12dec8
commit 344cd574a6
5 changed files with 661 additions and 0 deletions

View File

@ -37,6 +37,7 @@ SOURCES[] =
AgeChecker.cpp
NinjaCommunicator.cpp
SimpleXmlPreprocessor.cpp
PreorderTitleRestorer.cpp
NinjaXmlReader.cpp
../common/Util.cpp
../common/DrawSystemState.cpp

View File

@ -0,0 +1,381 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: PreorderTitleRestorer.cpp
Copyright (C)2015 Nintendo Co., Ltd. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include "PreorderTitleRestorer.h"
#include "NinjaCommunicator.h"
#include "NinjaXmlReader.h"
#include "CommonLogger.h"
#include "HeapManager.h"
#include <nn/fs/fs_ApiExternalSeeds.h>
#include <nn/fs/fs_ApiTitleTags.h>
#include <nn/nim/CTR/nim_PrepurchaseTitleTag.h>
#include <nn/nim/CTR/nim_ShopApi.h>
namespace ConsoleRestore
{
namespace
{
using namespace nn::cfg;
CfgCountryCode s_TypicalCountryCode[] = {
CFG_COUNTRY_JAPAN,
CFG_COUNTRY_UNITED_STATES,
CFG_COUNTRY_CANADA,
CFG_COUNTRY_MEXICO,
CFG_COUNTRY_AUSTRALIA,
CFG_COUNTRY_FRANCE,
CFG_COUNTRY_GERMANY,
CFG_COUNTRY_ITALY,
CFG_COUNTRY_NETHERLANDS,
CFG_COUNTRY_SPAIN,
CFG_COUNTRY_UNITED_KINGDOM,
CFG_COUNTRY_TAIWAN,
CFG_COUNTRY_SOUTH_KOREA,
CFG_COUNTRY_HONG_KONG,
CFG_COUNTRY_MACAU,
CFG_COUNTRY_CHINA
};
const size_t s_TypicalCountryCodeSize = sizeof(s_TypicalCountryCode) / sizeof(s_TypicalCountryCode[0]);
}
PreorderTitleRestorer::PreorderTitleRestorer()
{
}
PreorderTitleRestorer::~PreorderTitleRestorer()
{
}
nn::Result PreorderTitleRestorer::Execute(nn::ProgramId list[], size_t size, nn::cfg::CTR::CfgCountryCode country, nn::cfg::CTR::CfgRegionCode region)
{
for(s32 i = 0; i < size; ++i)
{
std::string xml;
nn::cfg::CfgCountryCode deliveredCountry;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetExternalSeedInfo(&deliveredCountry, xml, list[i], country, region));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
SetExternalSeedOrPlayableDate(list[i], deliveredCountry, xml));
}
return nn::ResultSuccess();
}
nn::Result PreorderTitleRestorer::GetExternalSeedInfo(
nn::cfg::CTR::CfgCountryCode* deliveredCountry,
std::string& xml,
nn::ProgramId programId,
nn::cfg::CTR::CfgCountryCode country,
nn::cfg::CTR::CfgRegionCode region)
{
std::string nsUid;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetNsUid(nsUid, programId));
if(country == nn::cfg::CFG_COUNTRY_UNDEFINED)
{
// 代表的な国で外部鍵の取得を試みた後、全ての国に対して繰り返しEcInfoを取得する
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetEcInfoAndCountryRepeatedly(xml, deliveredCountry, nsUid, region));
}
else
{
*deliveredCountry = country;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetEcInfo(xml, nsUid, country));
}
return nn::ResultSuccess();
}
nn::Result PreorderTitleRestorer::GetNsUid(std::string& nsUid, nn::ProgramId programId)
{
NinjaCommunicator ninja;
// ns_uidの取得
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.GetNsUid("https://ninja.ctr.shop.nintendo.net/ninja/ws/", programId));
size_t bufSize = 1024 * 1024; // 1MB
common::HeapManager heap(bufSize);
heap.GetAddr();
void* buf = heap.GetAddr();
if(!buf)
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.GetBody(reinterpret_cast<u8*>(buf), bufSize));
NN_LOG("%s\n", buf);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.Finalize());
NinjaXmlReader reader;
reader.GetNsUid(nsUid, reinterpret_cast<char*>(buf));
return nn::ResultSuccess();
}
nn::Result PreorderTitleRestorer::GetEcInfo(std::string& ecInfo, std::string nsUid, nn::cfg::CfgCountryCode country)
{
NinjaCommunicator ninja;
char iso3166a2[3];
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
nn::cfg::ConvertCountryCodeToIso3166a2(iso3166a2, country));
// ec_infoの取得
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.GetEcInfo("https://ninja.ctr.shop.nintendo.net/ninja/ws/", nsUid.c_str(), iso3166a2));
size_t bufSize = 1024 * 1024; // 1MB
common::HeapManager heap(bufSize);
heap.GetAddr();
void* buf = heap.GetAddr();
if(!buf)
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.GetBody(reinterpret_cast<u8*>(buf), bufSize));
NN_LOG("%s\n", buf);
ecInfo = reinterpret_cast<char*>(buf);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
ninja.Finalize());
return nn::ResultSuccess();
}
nn::Result PreorderTitleRestorer::GetEcInfoAndCountryRepeatedly(std::string& ecInfo, nn::cfg::CfgCountryCode* deliveredCountry, std::string nsUid, nn::cfg::CTR::CfgRegionCode region)
{
// 既に接続ダウンロード済みの国があればそれを試す
for(std::map<nn::cfg::CTR::CfgCountryCode, bool>::iterator it = m_SuccessfulCountryMap.begin(); it != m_SuccessfulCountryMap.end(); ++it)
{
if(IsValidCountry(it->first, region))
{
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetEcInfo(ecInfo, nsUid, it->first));
if (HasExternal_Seed(ecInfo))
{
*deliveredCountry = it->first;
return nn::ResultSuccess();
}
}
}
// 代表的な国からダウンロードを試す
for(s32 i = 0; i < s_TypicalCountryCodeSize; ++i)
{
if(IsValidCountry(s_TypicalCountryCode[i], region))
{
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetEcInfo(ecInfo, nsUid, s_TypicalCountryCode[i]));
if (HasExternal_Seed(ecInfo))
{
*deliveredCountry = s_TypicalCountryCode[i];
if(m_SuccessfulCountryMap.count(s_TypicalCountryCode[i]) == 0)
{
m_SuccessfulCountryMap.insert(std::make_pair(s_TypicalCountryCode[i], true));
}
return nn::ResultSuccess();
}
}
}
// 全ての国からダウンロードを試す
for(s32 i = CFG_COUNTRY_JAPAN; i < CFG_COUNTRY_UNKNOWN; ++i)
{
CfgCountryCode country = static_cast<CfgCountryCode>(i);
if(IsValidCountry(country, region))
{
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetEcInfo(ecInfo, nsUid, country));
if (HasExternal_Seed(ecInfo))
{
*deliveredCountry = country;
if(m_SuccessfulCountryMap.count(country) == 0)
{
m_SuccessfulCountryMap.insert(std::make_pair(country, true));
}
return nn::ResultSuccess();
}
}
}
return nn::ResultSuccess();
}
nn::Result PreorderTitleRestorer::SetExternalSeedOrPlayableDate(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country, std::string& xml)
{
// content_lockが無ければ何もしない
if (IsLocked(xml))
{
// external_seedが有れば外部鍵をインポート
if (HasExternal_Seed(xml))
{
NN_LOG("Importing External Seed for %016llx\n", programId);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
SetExternalKey(programId, country));
}
// external_seedが無ければタイトルタグを登録
else
{
NN_LOG("SetTitleTag for %x\n", programId);
SetTitleTag(programId, country, xml);
}
}
return nn::ResultSuccess();
}
bool PreorderTitleRestorer::IsLocked(std::string xml)
{
NinjaXmlReader reader;
return reader.HasContentLock(xml);
}
bool PreorderTitleRestorer::HasExternal_Seed(std::string xml)
{
NinjaXmlReader reader;
return reader.HasExternalSeed(xml);
}
nn::Result PreorderTitleRestorer::SetExternalKey(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country)
{
nn::nim::ResultError resultError;
resultError = nn::nim::CTR::Shop::ImportExternalSeed(programId, country);
if(resultError.IsFailure())
{
COMMON_LOGGER("ErrorCode:%d\n", resultError.GetErrorCode());
return resultError.GetResult();
}
return nn::ResultSuccess();
}
void PreorderTitleRestorer::SetTitleTag(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country, std::string xml)
{
NinjaXmlReader reader;
nn::fnd::DateTime playable = reader.GetPlayableDate(xml);
nn::fs::CTR::TitleTag titleTag;
nn::nim::CTR::MakePrepurchaseTitleTag(&titleTag, playable.GetYear(), playable.GetMonth(), playable.GetDay(), country);
nn::fs::SetTitleTag(programId, titleTag);
}
// Horizon\sources\tools\Config\UserInfoSetting.cppからのコピペ
bool PreorderTitleRestorer::IsValidCountry(nn::cfg::CTR::CfgCountryCode countryCode, nn::cfg::CTR::CfgRegionCode region)
{
using namespace nn::cfg::CTR;
if (countryCode == 0xFF)
{
return true;
}
// 対象リージョンで指定国が有効かどうかを判定
if (region == nn::cfg::CTR::CFG_REGION_JAPAN)
{
if (countryCode == nn::cfg::CTR::CFG_COUNTRY_JAPAN)
{
return true;
}
}
else if (region == nn::cfg::CTR::CFG_REGION_AMERICA)
{
if ((CFG_COUNTRY_MAPPING_AMERICA >> 16) <= countryCode && countryCode <= (CFG_COUNTRY_MAPPING_AMERICA & 0xFF))
{
return true;
}
switch (countryCode)
{
case CFG_COUNTRY_SINGAPORE:
case CFG_COUNTRY_MALAYSIA:
case CFG_COUNTRY_UAE:
case CFG_COUNTRY_SAUDI_ARABIA:
return true;
default:
;
}
}
else if (region == nn::cfg::CTR::CFG_REGION_EUROPE)
{
if ((CFG_COUNTRY_MAPPING_EUROPE >> 16) <= countryCode && countryCode <= (CFG_COUNTRY_MAPPING_EUROPE & 0xFF))
{
return true;
}
switch (countryCode)
{
case CFG_COUNTRY_INDIA:
case CFG_COUNTRY_SAN_MARINO:
case CFG_COUNTRY_VATICAN_CITY:
return true;
default:
;
}
}
else if (region == nn::cfg::CTR::CFG_REGION_CHINA)
{
switch (countryCode)
{
case CFG_COUNTRY_CHINA:
return true;
default:
;
}
}
else if (region == nn::cfg::CTR::CFG_REGION_KOREA)
{
switch (countryCode)
{
case CFG_COUNTRY_SOUTH_KOREA:
return true;
default:
;
}
}
else if (region == nn::cfg::CTR::CFG_REGION_TAIWAN)
{
switch (countryCode)
{
case CFG_COUNTRY_TAIWAN:
case CFG_COUNTRY_HONG_KONG:
return true;
default:
;
}
}
return false;
}
} /* namespace ConsoleRestore */

View File

@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: PreorderTitleRestorer.h
Copyright (C)2015 Nintendo Co., Ltd. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#ifndef SOURCES_CONSOLERESTORE_PREORDERTITLERESTORER_H_
#define SOURCES_CONSOLERESTORE_PREORDERTITLERESTORER_H_
#include <string>
#include <map>
#include <vector>
#include <nn/types.h>
#include <nn/fnd.h>
#include <nn/cfg.h>
#include <nn/CTR/CTR_ProgramId.h>
namespace ConsoleRestore
{
class PreorderTitleRestorer
{
public:
PreorderTitleRestorer();
virtual ~PreorderTitleRestorer();
//! @brief @予約販売タイトルの修復を行います
//! @param[in] list[] Personalized eTicketで権利を持っているタイトルの配列
//! @param[in] size listのサイズ
//! @param[in] country 国コード。国コードが取得できない場合はCFG_COUNTRY_UNDEFINEDを渡してください
//! @param[in] region リージョンコード
nn::Result Execute(nn::ProgramId list[], size_t size, nn::cfg::CTR::CfgCountryCode country, nn::cfg::CTR::CfgRegionCode region);
private:
nn::Result GetExternalSeedInfo(
nn::cfg::CTR::CfgCountryCode* deliveredCountry,
std::string& xml,
nn::ProgramId programId,
nn::cfg::CTR::CfgCountryCode country,
nn::cfg::CTR::CfgRegionCode region);
nn::Result GetNsUid(std::string& nsUid, nn::ProgramId programId);
nn::Result GetEcInfo(std::string& ecInfo, std::string nsUid, nn::cfg::CfgCountryCode country);
nn::Result SetExternalSeedOrPlayableDate(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country, std::string& xml);
nn::Result GetEcInfoAndCountryRepeatedly(std::string& ecInfo, nn::cfg::CfgCountryCode* deliveredCountry, std::string nsUid, nn::cfg::CTR::CfgRegionCode region);
bool IsLocked(std::string xml);
bool HasExternal_Seed(std::string xml);
nn::Result SetExternalKey(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country);
void SetTitleTag(nn::ProgramId programId, nn::cfg::CTR::CfgCountryCode country, std::string xml);
bool IsValidCountry(nn::cfg::CfgCountryCode countryCode, nn::cfg::CfgRegionCode region);
std::map<nn::cfg::CTR::CfgCountryCode, bool> m_SuccessfulCountryMap;
};
} /* namespace ConsoleRestore */
#endif /* SOURCES_CONSOLERESTORE_PREORDERTITLERESTORER_H_ */

View File

@ -0,0 +1,74 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakefile
#
# Copyright (C)2009 Nintendo Co., Ltd. All rights reserved.
#
# These coded instructions, statements, and computer programs contain
# proprietary information of Nintendo of America Inc. and/or Nintendo
# Company Ltd., and are protected by Federal copyright law. They may
# not be disclosed to third parties or copied or duplicated in any form,
# in whole or in part, without the prior written consent of Nintendo.
#
# $Rev$
#----------------------------------------------------------------------------
SUPPORTED_TARGETS = CTR-*.Process.MPCore.*
include $(makePlatformDefsPath tests)
SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include)
INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \
../../../common \
../../../ConsoleRestore \
TEST_COMMON_SOURCES[] =
../../../ConsoleRestore/TitleDownloader.cpp
../../../ConsoleRestore/Shop.cpp
../../../ConsoleRestore/PreinstallImporter.cpp
../../../ConsoleRestore/NinjaCommunicator.cpp
../../../ConsoleRestore/SimpleXmlPreprocessor.cpp
../../../ConsoleRestore/NinjaXmlReader.cpp
../../../ConsoleRestore/PreorderTitleRestorer.cpp
../../../common/Util.cpp
../../../common/HeapManager.cpp
../../../common/SdLogger.cpp
../../../common/LogConsole.cpp
../../../common/CommonLogger.cpp
../../../common/SdMountManager.cpp
../../../common/VersionDetect.cpp
../../../common/HardwareStateManager.cpp
../../../common/FileTransfer.cpp
../../../common/SdReaderWriter.cpp
CCFLAGS += -DCOMMON_LOGGER_DETAIL_ENABLE
include $(ROOT)/common/BuildSwitch.om
SOURCES_TEST[] = test_PreorderTitleRestorer.cpp
ROMFS_ROOT = ../../../common/romfiles
TEST_ENVIRONMENT_PROCESSLIST = true
TEST_ENVIRONMENT_EMUMEM = true
EXCLUDE_LIBS += libnn_olv
LIBS += libnn_test \
libnn_mcu \
libnn_ps \
libnn_am \
lib_demo \
libnn_nim \
libnn_xml_simple \
ROM_SPEC_FILE = ../../../ConsoleRestore/ConsoleRestore.rsf
DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/tools/RepairTool.desc
include $(makePlatformDefsPath build.tests)
tests: $(TEST_TARGETS)

View File

@ -0,0 +1,141 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: test_NinjaCommunicator.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn.h>
#include <nn/test/test_Test.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/fs.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/am.h>
#include <nn/nim.h>
#include "demo.h"
#include "common_Types.h"
#include "CommonLogger.h"
#include "HeapManager.h"
#include "PreorderTitleRestorer.h"
using namespace nn::test;
class TestPreorderTitleRestorer : public Suite {
public:
virtual bool InitializeSuite();
virtual void FinalizeSuite();
TestPreorderTitleRestorer() {
SUITE_NAME("Test");
TEST_ADD(TestPreorderTitleRestorer::ExecuteUsingAlreadyDeliveredTitle);
//TEST_ADD(TestPreorderTitleRestorer::ExecuteUsingPreorderedTitle);
TEST_ADD(TestPreorderTitleRestorer::ExecuteWithInvalidCountry);
}
private:
void ExecuteUsingAlreadyDeliveredTitle();
void ExecuteUsingPreorderedTitle();
void ExecuteWithInvalidCountry();
};
namespace
{
const size_t s_GxHeapSize = 0x800000;
}
//------------------------------------------------------------------
// Initialize/Finalize
//------------------------------------------------------------------
bool TestPreorderTitleRestorer::InitializeSuite()
{
// os の初期化
nn::fs::Initialize();
nn::cfg::CTR::init::Initialize();
nn::cfg::CTR::system::Initialize();
// nimの初期化
nn::nim::InitializeForShop();
// ヒープの確保
common::InitializeHeap();
common::HeapManager gxHeap(s_GxHeapSize);
// RenderSystem の準備
uptr heapForGx = reinterpret_cast<uptr>(gxHeap.GetAddr());
demo::RenderSystemDrawing renderSystem;
renderSystem.Initialize(heapForGx, s_GxHeapSize);
// ログ描画の初期化
common::Logger::GetLoggerInstance()->Initialize(common::CONSOLE_WIDTH, common::CONSOLE_HEIGHT,
common::CONSOLE_MAX_LINE, &renderSystem);
return true;
}
void TestPreorderTitleRestorer::FinalizeSuite()
{
}
//------------------------------------------------------------------
// Test Util
//------------------------------------------------------------------
//------------------------------------------------------------------
// Test Functions
//------------------------------------------------------------------
void TestPreorderTitleRestorer::ExecuteUsingAlreadyDeliveredTitle()
{
nn::ProgramId list[] = { 0x000400000FECD100 };
ConsoleRestore::PreorderTitleRestorer ptr;
NN_TEST_ASSERT(
ptr.Execute(list, sizeof(list) / sizeof(list[0]), nn::cfg::CTR::CFG_COUNTRY_JAPAN, nn::cfg::CTR::CFG_REGION_JAPAN).IsSuccess());
}
void TestPreorderTitleRestorer::ExecuteUsingPreorderedTitle()
{
nn::ProgramId list[] = { 0x000400000FECD000 };
ConsoleRestore::PreorderTitleRestorer ptr;
NN_TEST_ASSERT(
ptr.Execute(list, sizeof(list) / sizeof(list[0]), nn::cfg::CTR::CFG_COUNTRY_JAPAN, nn::cfg::CTR::CFG_REGION_JAPAN).IsSuccess());
}
void TestPreorderTitleRestorer::ExecuteWithInvalidCountry()
{
nn::ProgramId list[] = { 0x000400000FECD100 };
ConsoleRestore::PreorderTitleRestorer ptr;
NN_TEST_ASSERT(
ptr.Execute(list, sizeof(list) / sizeof(list[0]), nn::cfg::CTR::CFG_COUNTRY_UNDEFINED, nn::cfg::CTR::CFG_REGION_JAPAN).IsSuccess());
NN_TEST_ASSERT(
ptr.Execute(list, sizeof(list) / sizeof(list[0]), nn::cfg::CTR::CFG_COUNTRY_UNDEFINED, nn::cfg::CTR::CFG_REGION_AMERICA).IsSuccess());
NN_TEST_ASSERT(
ptr.Execute(list, sizeof(list) / sizeof(list[0]), nn::cfg::CTR::CFG_COUNTRY_UNDEFINED, nn::cfg::CTR::CFG_REGION_EUROPE).IsSuccess());
}
NN_TEST_DEFINE_MAIN(TestPreorderTitleRestorer)
/*---------------------------------------------------------------------------*
End of file
*---------------------------------------------------------------------------*/