Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
8.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "CDKeyEntryDialog.h"
  8. #include "EngineInterface.h"
  9. #include "steamcommon.h" // VALVE_AUTH cd key checking code
  10. #include "ValidateNewValveCDKeyClient.h"
  11. #include "ValveCDKeyGameAndTerritoryCodes.h"
  12. #include "vgui/IInput.h"
  13. #include "vgui/IPanel.h"
  14. #include "vgui/ISystem.h"
  15. #include "vgui/ISurface.h"
  16. #include "vgui_controls/Button.h"
  17. #include "vgui_controls/MessageBox.h"
  18. #include "vgui_controls/TextEntry.h"
  19. #include "vstdlib/random.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. #include <ctype.h>
  23. using namespace vgui;
  24. #define FAKE_CDKEY_LEN 49
  25. #define FAKE_CDKEY_REGKEY "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Settings\\EncryptedCDKey"
  26. //-----------------------------------------------------------------------------
  27. // Purpose: hacky class to make all input uppercase
  28. //-----------------------------------------------------------------------------
  29. class CUpperCaseTextEntry : public vgui::TextEntry
  30. {
  31. DECLARE_CLASS_SIMPLE( CUpperCaseTextEntry, vgui::TextEntry );
  32. public:
  33. CUpperCaseTextEntry(vgui::Panel *parent, const char *name) : TextEntry(parent, name) {}
  34. virtual void InsertChar(wchar_t unichar)
  35. {
  36. // only allow input of valid cdkey characters
  37. if (unichar >= 'a' && unichar <= 'z')
  38. {
  39. // force to be uppercase
  40. BaseClass::InsertChar(unichar - 'a' + 'A');
  41. }
  42. else if ((unichar >= 'A' && unichar <= 'Z')
  43. || (unichar >= '0' && unichar <= '9'))
  44. {
  45. BaseClass::InsertChar(unichar);
  46. }
  47. }
  48. };
  49. class CloseMessageBox : public vgui::MessageBox
  50. {
  51. public:
  52. CloseMessageBox(const char *title, const char *text, Panel *parent = NULL): MessageBox( title, text, parent) {}
  53. virtual void OnClose()
  54. {
  55. engine->ClientCmd_Unrestricted("quit\n");
  56. }
  57. };
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Constructor
  60. //-----------------------------------------------------------------------------
  61. CCDKeyEntryDialog::CCDKeyEntryDialog(vgui::Panel *parent, bool inConnect) : BaseClass(parent, "CDKeyEntryDialog")
  62. {
  63. // see what type of cdkey we have
  64. SetDeleteSelfOnClose(true);
  65. m_bInConnect = inConnect;
  66. m_iErrCount = 0;
  67. m_bEnteredValidCDKey = false;
  68. m_pOK = new Button(this, "OKButton", "#GameUI_OK");
  69. m_pQuitGame = new Button(this, "CancelButton", "#GameUI_Quit");
  70. m_pEntry1 = new CUpperCaseTextEntry(this, "Entry1");;
  71. m_pEntry2 = new CUpperCaseTextEntry(this, "Entry2");
  72. m_pEntry3 = new CUpperCaseTextEntry(this, "Entry3");
  73. m_pEntry4 = new CUpperCaseTextEntry(this, "Entry4");
  74. m_pEntry5 = new CUpperCaseTextEntry(this, "Entry5");
  75. m_pEntry1->SetMaximumCharCount(5);
  76. m_pEntry2->SetMaximumCharCount(5);
  77. m_pEntry3->SetMaximumCharCount(5);
  78. m_pEntry4->SetMaximumCharCount(5);
  79. m_pEntry5->SetMaximumCharCount(5);
  80. m_pEntry1->SetAutoProgressOnHittingCharLimit(true);
  81. m_pEntry2->SetAutoProgressOnHittingCharLimit(true);
  82. m_pEntry3->SetAutoProgressOnHittingCharLimit(true);
  83. m_pEntry4->SetAutoProgressOnHittingCharLimit(true);
  84. m_pEntry5->SetAutoProgressOnHittingCharLimit(false);
  85. SetSizeable(false);
  86. SetSize(360, 224);
  87. SetTitle("#GameUI_CDKey", true);
  88. LoadControlSettings("Resource/ValveCDKeyEntryDialog.res");
  89. // MoveToCenterOfScreen();
  90. SetMinimizeButtonVisible(false);
  91. SetMaximizeButtonVisible(false);
  92. m_pOK->SetEnabled(false);
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Destructor
  96. //-----------------------------------------------------------------------------
  97. CCDKeyEntryDialog::~CCDKeyEntryDialog()
  98. {
  99. vgui::surface()->RestrictPaintToSinglePanel(NULL);
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: returns true if there is a valid weak check key in the registry
  103. //-----------------------------------------------------------------------------
  104. bool CCDKeyEntryDialog::IsValidWeakCDKeyInRegistry()
  105. {
  106. char fakekey[FAKE_CDKEY_LEN];
  107. if (vgui::system()->GetRegistryString(FAKE_CDKEY_REGKEY, fakekey, sizeof(fakekey)))
  108. {
  109. if (strlen(fakekey) == (FAKE_CDKEY_LEN - 1)
  110. && fakekey[17] == 'E'
  111. && fakekey[31] == 'z'
  112. && fakekey[43] == 'n')
  113. {
  114. return true;
  115. }
  116. }
  117. return false;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose:
  121. //-----------------------------------------------------------------------------
  122. void CCDKeyEntryDialog::OnCommand(const char *command)
  123. {
  124. if (!stricmp(command, "OK"))
  125. {
  126. if (IsEnteredKeyValid())
  127. {
  128. m_bEnteredValidCDKey = true;
  129. // write out fake key and continue
  130. char fakekey[FAKE_CDKEY_LEN];
  131. for (int i = 0; i < sizeof(fakekey) - 1; i++)
  132. {
  133. // pick some random fields for us to check later
  134. if (i == 17)
  135. {
  136. fakekey[i] = 'E';
  137. }
  138. else if (i == 31)
  139. {
  140. fakekey[i] = 'z';
  141. }
  142. else if (i == 43)
  143. {
  144. fakekey[i] = 'n';
  145. }
  146. else
  147. {
  148. fakekey[i] = RandomInt('0', 'z');
  149. }
  150. }
  151. fakekey[sizeof(fakekey) - 1] = 0;
  152. vgui::system()->SetRegistryString(FAKE_CDKEY_REGKEY, fakekey);
  153. if ( m_bInConnect )
  154. {
  155. engine->ClientCmd_Unrestricted( "retry\n" ); // retry the server connection with this new key...
  156. }
  157. Close();
  158. }
  159. else
  160. {
  161. m_hErrorBox = new MessageBox("#GameUI_CDKey_Invalid_Title","#GameUI_CDKey_Invalid_Text", this);
  162. m_hErrorBox->ShowWindow( this );
  163. }
  164. }
  165. else if (!stricmp(command, "Cancel") || !stricmp(command, "Close"))
  166. {
  167. Close();
  168. }
  169. else
  170. {
  171. BaseClass::OnCommand(command);
  172. }
  173. if (!m_bEnteredValidCDKey) // moved away from the dialog box to make it a little harder to crack...
  174. {
  175. m_iErrCount++;
  176. if( m_iErrCount >= MAX_CDKEY_ERRORS )
  177. {
  178. // too many bad entries, make em quit
  179. CloseMessageBox *bx = new CloseMessageBox("#GameUI_CDKey_Invalid_Title","#GameUI_CDKey_TooManyTries", this);
  180. bx->ShowWindow( this );
  181. }
  182. }
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose:
  186. //-----------------------------------------------------------------------------
  187. void CCDKeyEntryDialog::OnClose()
  188. {
  189. if (!m_bEnteredValidCDKey)
  190. {
  191. // if we don't have a valid key we can't continue
  192. engine->ClientCmd_Unrestricted("quit\n");
  193. }
  194. BaseClass::OnClose();
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. //-----------------------------------------------------------------------------
  199. void CCDKeyEntryDialog::OnThink()
  200. {
  201. if (!m_bEnteredValidCDKey)
  202. {
  203. // force us to be the only thing to draw
  204. VPANEL vpanel = m_hErrorBox.Get() ? m_hErrorBox->GetVPanel() : GetVPanel();
  205. vgui::surface()->RestrictPaintToSinglePanel(vpanel);
  206. // make sure we're the focus
  207. if (!(input()->GetFocus() && ipanel()->HasParent(input()->GetFocus(), GetVPanel())))
  208. {
  209. BaseClass::Activate();
  210. }
  211. }
  212. BaseClass::OnThink();
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: returns whether or not the key entered by the user passes the simple check
  216. //-----------------------------------------------------------------------------
  217. bool CCDKeyEntryDialog::IsEnteredKeyValid()
  218. {
  219. // get the entered text
  220. char cdkey[32];
  221. m_pEntry1->GetText(cdkey, 6);
  222. m_pEntry2->GetText(cdkey + 6, 6);
  223. m_pEntry3->GetText(cdkey + 12, 6);
  224. m_pEntry4->GetText(cdkey + 18, 6);
  225. m_pEntry5->GetText(cdkey + 24, 6);
  226. // add in the hyphens
  227. cdkey[5] = '-';
  228. cdkey[11] = '-';
  229. cdkey[17] = '-';
  230. cdkey[23] = '-';
  231. // verify the entry
  232. for (int i = 0; i < 29; i++)
  233. {
  234. if (cdkey[i] != '-' && !isalnum(cdkey[i]))
  235. return false;
  236. }
  237. #if !defined( NO_STEAM )
  238. uint gameCode, salesTerritoryCode, uniqueSerialNumber;
  239. // test key - this key passes they weak check, but not the strong check
  240. // "5J5Q3-QCME2-2SMMV-SBHN9-43S2S"
  241. if ( SteamWeakVerifyNewValveCDKey(cdkey, &gameCode, &salesTerritoryCode, &uniqueSerialNumber) == eSteamErrorNone )
  242. {
  243. // require hl2 retail cdkey (ATI Bundle keys are also in this category)
  244. if (gameCode == eHalfLife2)
  245. return true;
  246. }
  247. #endif
  248. return false;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: handles user entering data in fields
  252. //-----------------------------------------------------------------------------
  253. void CCDKeyEntryDialog::OnTextChanged(Panel *entry)
  254. {
  255. char cdkey[32];
  256. m_pEntry1->GetText(cdkey, 6);
  257. m_pEntry2->GetText(cdkey + 6, 6);
  258. m_pEntry3->GetText(cdkey + 12, 6);
  259. m_pEntry4->GetText(cdkey + 18, 6);
  260. m_pEntry5->GetText(cdkey + 24, 6);
  261. // add in the hyphens
  262. cdkey[5] = '-';
  263. cdkey[11] = '-';
  264. cdkey[17] = '-';
  265. cdkey[23] = '-';
  266. if (strlen(cdkey) == 29)
  267. {
  268. m_pOK->SetEnabled(true);
  269. }
  270. else
  271. {
  272. m_pOK->SetEnabled(false);
  273. }
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose:
  277. //-----------------------------------------------------------------------------
  278. void CCDKeyEntryDialog::Activate()
  279. {
  280. BaseClass::Activate();
  281. m_pEntry1->RequestFocus();
  282. }