Index: source/lib/sysdep/os/unix/unix.cpp
===================================================================
--- source/lib/sysdep/os/unix/unix.cpp
+++ source/lib/sysdep/os/unix/unix.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2021 Wildfire Games.
+/* Copyright (c) 2022 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -320,29 +320,6 @@
return L"";
}
-Status sys_generate_random_bytes(u8* buf, size_t count)
-{
- FILE* f = fopen("/dev/urandom", "rb");
- if (!f)
- WARN_RETURN(ERR::FAIL);
-
- while (count)
- {
- size_t numread = fread(buf, 1, count, f);
- if (numread == 0)
- {
- fclose(f);
- WARN_RETURN(ERR::FAIL);
- }
- buf += numread;
- count -= numread;
- }
-
- fclose(f);
-
- return INFO::OK;
-}
-
Status sys_get_proxy_config(const std::wstring& UNUSED(url), std::wstring& UNUSED(proxy))
{
return INFO::SKIPPED;
Index: source/lib/sysdep/os/win/wsysdep.cpp
===================================================================
--- source/lib/sysdep/os/win/wsysdep.cpp
+++ source/lib/sysdep/os/win/wsysdep.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -503,23 +503,6 @@
}
-Status sys_generate_random_bytes(u8* buffer, size_t size)
-{
- HCRYPTPROV hCryptProv = 0;
- if(!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
- WARN_RETURN(StatusFromWin());
-
- memset(buffer, 0, size);
- if(!CryptGenRandom(hCryptProv, (DWORD)size, (BYTE*)buffer))
- WARN_RETURN(StatusFromWin());
-
- if(!CryptReleaseContext(hCryptProv, 0))
- WARN_RETURN(StatusFromWin());
-
- return INFO::OK;
-}
-
-
#if CONFIG_ENABLE_BOOST
/*
Index: source/lib/sysdep/sysdep.h
===================================================================
--- source/lib/sysdep/sysdep.h
+++ source/lib/sysdep/sysdep.h
@@ -157,14 +157,6 @@
**/
extern size_t sys_max_sector_size();
-/**
- * generate high-quality random bytes.
- *
- * this should only be used with small numbers of bytes, to avoid
- * hogging the system's entropy.
- **/
-Status sys_generate_random_bytes(u8* buf, size_t count);
-
/**
* get the proxy address for accessing the given HTTP URL.
*
Index: source/lib/sysdep/tests/test_sysdep.h
===================================================================
--- source/lib/sysdep/tests/test_sysdep.h
+++ source/lib/sysdep/tests/test_sysdep.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -37,14 +37,6 @@
class TestSysdep : public CxxTest::TestSuite
{
public:
- void test_random()
- {
- u64 a = 0, b = 0;
- TS_ASSERT_OK(sys_generate_random_bytes((u8*)&a, sizeof(a)));
- TS_ASSERT_OK(sys_generate_random_bytes((u8*)&b, sizeof(b)));
- TS_ASSERT_DIFFERS(a, b);
- }
-
void test_sys_ExecutablePathname()
{
OsPath path = sys_ExecutablePathname();
Index: source/lobby/XmppClient.cpp
===================================================================
--- source/lobby/XmppClient.cpp
+++ source/lobby/XmppClient.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -106,7 +106,7 @@
m_xpartamuppId = sXpartamupp + "@" + m_server + "/CC";
m_echelonId = sEchelon + "@" + m_server + "/CC";
// Generate a unique, unpredictable resource to allow multiple 0 A.D. instances to connect to the lobby.
- glooxwrapper::JID clientJid(sUsername + "@" + m_server + "/0ad-" + ps_generate_guid());
+ glooxwrapper::JID clientJid(sUsername + "@" + m_server + "/0ad-" + PS::GenerateGUID());
glooxwrapper::JID roomJid(m_room + "@conference." + m_server + "/" + sNick);
// If we are connecting, use the full jid and a password
Index: source/network/NetServer.cpp
===================================================================
--- source/network/NetServer.cpp
+++ source/network/NetServer.cpp
@@ -938,7 +938,7 @@
return false;
}
- CStr guid = ps_generate_guid();
+ CStr guid = PS::GenerateGUID();
int count = 0;
// Ensure unique GUID
while(std::find_if(
@@ -951,7 +951,7 @@
session->Disconnect(NDR_GUID_FAILED);
return true;
}
- guid = ps_generate_guid();
+ guid = PS::GenerateGUID();
}
session->SetGUID(guid);
Index: source/network/scripting/JSInterface_Network.cpp
===================================================================
--- source/network/scripting/JSInterface_Network.cpp
+++ source/network/scripting/JSInterface_Network.cpp
@@ -97,7 +97,7 @@
}
// Generate a secret to identify the host client.
- std::string secret = ps_generate_guid();
+ std::string secret = PS::GenerateGUID();
g_NetServer->SetControllerSecret(secret);
g_Game = new CGame(storeReplay);
Index: source/ps/GUID.h
===================================================================
--- source/ps/GUID.h
+++ source/ps/GUID.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -20,6 +20,9 @@
#include "ps/CStr.h"
-CStr8 ps_generate_guid(void);
+namespace PS
+{
+CStr GenerateGUID();
+}
#endif
Index: source/ps/GUID.cpp
===================================================================
--- source/ps/GUID.cpp
+++ source/ps/GUID.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -15,27 +15,41 @@
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
-#include "lib/sysdep/sysdep.h"
-#include "ps/CStr.h"
-CStr ps_generate_guid(void)
+#include "ps/GUID.h"
+
+#include
+#include
+#include
+
+// TODO: Ideally this will be guaranteed unique (and verified
+// cryptographically) since we'll rely on it to identify hosts
+// and associate them with player controls (e.g. to support
+// leaving/rejoining in-progress games), and we don't want
+// a host to masquerade as someone else.
+// For now, just try to pick a very random number.
+
+namespace PS
+{
+static u64 GenerateGUIDNumber()
{
- // TODO: Ideally this will be guaranteed unique (and verified
- // cryptographically) since we'll rely on it to identify hosts
- // and associate them with player controls (e.g. to support
- // leaving/rejoining in-progress games), and we don't want
- // a host to masquerade as someone else.
- // For now, just try to pick a very random number.
+ std::random_device rd;
+ std::uniform_int_distribution distrib;
- CStr guid;
- for (size_t i = 0; i < 2; ++i)
+ if (rd.entropy() > 0)
+ return distrib(rd);
+
+ std::default_random_engine fallback
{
- u32 r = 0;
- sys_generate_random_bytes((u8*)&r, sizeof(r));
- char buf[32];
- sprintf_s(buf, ARRAY_SIZE(buf), "%08X", r);
- guid += buf;
- }
+ static_cast(
+ std::chrono::high_resolution_clock::now().time_since_epoch().count())
+ };
+ return distrib(fallback);
+}
- return guid;
+CStr GenerateGUID()
+{
+ const u64 r = GenerateGUIDNumber();
+ return fmt::format("{:016X}", r);
+}
}
Index: source/ps/UserReport.h
===================================================================
--- source/ps/UserReport.h
+++ source/ps/UserReport.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,7 +18,7 @@
#ifndef INCLUDED_USERREPORT
#define INCLUDED_USERREPORT
-#include
+#include "ps/CStr.h"
class CUserReporterWorker;
@@ -55,7 +55,7 @@
void SubmitReport(const std::string& type, int version, const std::string& data, const std::string& dataHumanReadable);
private:
- std::string LoadUserID();
+ CStr LoadUserID();
CUserReporterWorker* m_Worker;
};
Index: source/ps/UserReport.cpp
===================================================================
--- source/ps/UserReport.cpp
+++ source/ps/UserReport.cpp
@@ -28,6 +28,7 @@
#include "lib/sysdep/sysdep.h"
#include "ps/ConfigDB.h"
#include "ps/Filesystem.h"
+#include "ps/GUID.h"
#include "ps/Profiler2.h"
#include "ps/Pyrogenesis.h"
#include "ps/Threading.h"
@@ -91,7 +92,7 @@
class CUserReporterWorker
{
public:
- CUserReporterWorker(const std::string& userID, const std::string& url) :
+ CUserReporterWorker(const CStr& userID, const CStr& url) :
m_URL(url), m_UserID(userID), m_Enabled(false), m_Shutdown(false), m_Status("disabled"),
m_PauseUntilTime(timer_Time()), m_LastUpdateTime(timer_Time())
{
@@ -516,33 +517,23 @@
ENSURE(!m_Worker); // Deinitialize should have been called before shutdown
}
-std::string CUserReporter::LoadUserID()
+CStr CUserReporter::LoadUserID()
{
- std::string userID;
+ CStr userID;
// Read the user ID from user.cfg (if there is one)
CFG_GET_VAL("userreport.id", userID);
- // If we don't have a validly-formatted user ID, generate a new one
- if (userID.length() != 16)
- {
- u8 bytes[8] = {0};
- sys_generate_random_bytes(bytes, ARRAY_SIZE(bytes));
- // ignore failures - there's not much we can do about it
+ if (userID.length() == 16)
+ return userID;
- userID = "";
- for (size_t i = 0; i < ARRAY_SIZE(bytes); ++i)
- {
- char hex[3];
- sprintf_s(hex, ARRAY_SIZE(hex), "%02x", (unsigned int)bytes[i]);
- userID += hex;
- }
+ // We don't have a validly-formatted user ID, generate a new one
+ const CStr newUserID = PS::GenerateGUID();
- g_ConfigDB.SetValueString(CFG_USER, "userreport.id", userID);
- g_ConfigDB.WriteValueToFile(CFG_USER, "userreport.id", userID);
- }
+ g_ConfigDB.SetValueString(CFG_USER, "userreport.id", newUserID);
+ g_ConfigDB.WriteValueToFile(CFG_USER, "userreport.id", newUserID);
- return userID;
+ return newUserID;
}
bool CUserReporter::IsReportingEnabled()
@@ -574,8 +565,8 @@
{
ENSURE(!m_Worker); // must only be called once
- std::string userID = LoadUserID();
- std::string url;
+ CStr userID = LoadUserID();
+ CStr url;
CFG_GET_VAL("userreport.url_upload", url);
m_Worker = new CUserReporterWorker(userID, url);
Index: source/ps/scripting/JSInterface_Main.cpp
===================================================================
--- source/ps/scripting/JSInterface_Main.cpp
+++ source/ps/scripting/JSInterface_Main.cpp
@@ -71,7 +71,7 @@
std::wstring GetMatchID()
{
- return ps_generate_guid().FromUTF8();
+ return PS::GenerateGUID().FromUTF8();
}
JS::Value LoadMapSettings(const ScriptInterface& scriptInterface, const VfsPath& pathname)
Index: source/ps/tests/test_GUID.h
===================================================================
--- /dev/null
+++ source/ps/tests/test_GUID.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2022 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "lib/self_test.h"
+
+#include "ps/GUID.h"
+
+class TestGUID : public CxxTest::TestSuite
+{
+public:
+ void test_GUID()
+ {
+ const CStr testAgainst = PS::GenerateGUID();
+ for(size_t i = 0; i != 100; ++i)
+ {
+ TS_ASSERT_DIFFERS(PS::GenerateGUID(), testAgainst);
+ }
+ }
+};