database-files.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. Minetest
  3. Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include <cassert>
  17. #include <json/json.h>
  18. #include "database-files.h"
  19. #include "remoteplayer.h"
  20. #include "settings.h"
  21. #include "porting.h"
  22. #include "filesys.h"
  23. #include "server/player_sao.h"
  24. #include "util/string.h"
  25. // !!! WARNING !!!
  26. // This backend is intended to be used on Minetest 0.4.16 only for the transition backend
  27. // for player files
  28. PlayerDatabaseFiles::PlayerDatabaseFiles(const std::string &savedir) : m_savedir(savedir)
  29. {
  30. fs::CreateDir(m_savedir);
  31. }
  32. void PlayerDatabaseFiles::serialize(std::ostringstream &os, RemotePlayer *player)
  33. {
  34. // Utilize a Settings object for storing values
  35. Settings args;
  36. args.setS32("version", 1);
  37. args.set("name", player->getName());
  38. sanity_check(player->getPlayerSAO());
  39. args.setU16("hp", player->getPlayerSAO()->getHP());
  40. args.setV3F("position", player->getPlayerSAO()->getBasePosition());
  41. args.setFloat("pitch", player->getPlayerSAO()->getLookPitch());
  42. args.setFloat("yaw", player->getPlayerSAO()->getRotation().Y);
  43. args.setU16("breath", player->getPlayerSAO()->getBreath());
  44. std::string extended_attrs;
  45. player->serializeExtraAttributes(extended_attrs);
  46. args.set("extended_attributes", extended_attrs);
  47. args.writeLines(os);
  48. os << "PlayerArgsEnd\n";
  49. player->inventory.serialize(os);
  50. }
  51. void PlayerDatabaseFiles::savePlayer(RemotePlayer *player)
  52. {
  53. fs::CreateDir(m_savedir);
  54. std::string savedir = m_savedir + DIR_DELIM;
  55. std::string path = savedir + player->getName();
  56. bool path_found = false;
  57. RemotePlayer testplayer("", NULL);
  58. for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES && !path_found; i++) {
  59. if (!fs::PathExists(path)) {
  60. path_found = true;
  61. continue;
  62. }
  63. // Open and deserialize file to check player name
  64. std::ifstream is(path.c_str(), std::ios_base::binary);
  65. if (!is.good()) {
  66. errorstream << "Failed to open " << path << std::endl;
  67. return;
  68. }
  69. testplayer.deSerialize(is, path, NULL);
  70. is.close();
  71. if (strcmp(testplayer.getName(), player->getName()) == 0) {
  72. path_found = true;
  73. continue;
  74. }
  75. path = savedir + player->getName() + itos(i);
  76. }
  77. if (!path_found) {
  78. errorstream << "Didn't find free file for player " << player->getName()
  79. << std::endl;
  80. return;
  81. }
  82. // Open and serialize file
  83. std::ostringstream ss(std::ios_base::binary);
  84. serialize(ss, player);
  85. if (!fs::safeWriteToFile(path, ss.str())) {
  86. infostream << "Failed to write " << path << std::endl;
  87. }
  88. player->onSuccessfulSave();
  89. }
  90. bool PlayerDatabaseFiles::removePlayer(const std::string &name)
  91. {
  92. std::string players_path = m_savedir + DIR_DELIM;
  93. std::string path = players_path + name;
  94. RemotePlayer temp_player("", NULL);
  95. for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
  96. // Open file and deserialize
  97. std::ifstream is(path.c_str(), std::ios_base::binary);
  98. if (!is.good())
  99. continue;
  100. temp_player.deSerialize(is, path, NULL);
  101. is.close();
  102. if (temp_player.getName() == name) {
  103. fs::DeleteSingleFileOrEmptyDirectory(path);
  104. return true;
  105. }
  106. path = players_path + name + itos(i);
  107. }
  108. return false;
  109. }
  110. bool PlayerDatabaseFiles::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
  111. {
  112. std::string players_path = m_savedir + DIR_DELIM;
  113. std::string path = players_path + player->getName();
  114. const std::string player_to_load = player->getName();
  115. for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
  116. // Open file and deserialize
  117. std::ifstream is(path.c_str(), std::ios_base::binary);
  118. if (!is.good())
  119. continue;
  120. player->deSerialize(is, path, sao);
  121. is.close();
  122. if (player->getName() == player_to_load)
  123. return true;
  124. path = players_path + player_to_load + itos(i);
  125. }
  126. infostream << "Player file for player " << player_to_load << " not found" << std::endl;
  127. return false;
  128. }
  129. void PlayerDatabaseFiles::listPlayers(std::vector<std::string> &res)
  130. {
  131. std::vector<fs::DirListNode> files = fs::GetDirListing(m_savedir);
  132. // list files into players directory
  133. for (std::vector<fs::DirListNode>::const_iterator it = files.begin(); it !=
  134. files.end(); ++it) {
  135. // Ignore directories
  136. if (it->dir)
  137. continue;
  138. const std::string &filename = it->name;
  139. std::string full_path = m_savedir + DIR_DELIM + filename;
  140. std::ifstream is(full_path.c_str(), std::ios_base::binary);
  141. if (!is.good())
  142. continue;
  143. RemotePlayer player(filename.c_str(), NULL);
  144. // Null env & dummy peer_id
  145. PlayerSAO playerSAO(NULL, &player, 15789, false);
  146. player.deSerialize(is, "", &playerSAO);
  147. is.close();
  148. res.emplace_back(player.getName());
  149. }
  150. }
  151. AuthDatabaseFiles::AuthDatabaseFiles(const std::string &savedir) : m_savedir(savedir)
  152. {
  153. readAuthFile();
  154. }
  155. bool AuthDatabaseFiles::getAuth(const std::string &name, AuthEntry &res)
  156. {
  157. const auto res_i = m_auth_list.find(name);
  158. if (res_i == m_auth_list.end()) {
  159. return false;
  160. }
  161. res = res_i->second;
  162. return true;
  163. }
  164. bool AuthDatabaseFiles::saveAuth(const AuthEntry &authEntry)
  165. {
  166. m_auth_list[authEntry.name] = authEntry;
  167. // save entire file
  168. return writeAuthFile();
  169. }
  170. bool AuthDatabaseFiles::createAuth(AuthEntry &authEntry)
  171. {
  172. m_auth_list[authEntry.name] = authEntry;
  173. // save entire file
  174. return writeAuthFile();
  175. }
  176. bool AuthDatabaseFiles::deleteAuth(const std::string &name)
  177. {
  178. if (!m_auth_list.erase(name)) {
  179. // did not delete anything -> hadn't existed
  180. return false;
  181. }
  182. return writeAuthFile();
  183. }
  184. void AuthDatabaseFiles::listNames(std::vector<std::string> &res)
  185. {
  186. res.clear();
  187. res.reserve(m_auth_list.size());
  188. for (const auto &res_pair : m_auth_list) {
  189. res.push_back(res_pair.first);
  190. }
  191. }
  192. void AuthDatabaseFiles::reload()
  193. {
  194. readAuthFile();
  195. }
  196. bool AuthDatabaseFiles::readAuthFile()
  197. {
  198. std::string path = m_savedir + DIR_DELIM + "auth.txt";
  199. std::ifstream file(path, std::ios::binary);
  200. if (!file.good()) {
  201. return false;
  202. }
  203. m_auth_list.clear();
  204. while (file.good()) {
  205. std::string line;
  206. std::getline(file, line);
  207. std::vector<std::string> parts = str_split(line, ':');
  208. if (parts.size() < 3) // also: empty line at end
  209. continue;
  210. const std::string &name = parts[0];
  211. const std::string &password = parts[1];
  212. std::vector<std::string> privileges = str_split(parts[2], ',');
  213. s64 last_login = parts.size() > 3 ? atol(parts[3].c_str()) : 0;
  214. m_auth_list[name] = {
  215. 1,
  216. name,
  217. password,
  218. privileges,
  219. last_login,
  220. };
  221. }
  222. return true;
  223. }
  224. bool AuthDatabaseFiles::writeAuthFile()
  225. {
  226. std::string path = m_savedir + DIR_DELIM + "auth.txt";
  227. std::ostringstream output(std::ios_base::binary);
  228. for (const auto &auth_i : m_auth_list) {
  229. const AuthEntry &authEntry = auth_i.second;
  230. output << authEntry.name << ":" << authEntry.password << ":";
  231. output << str_join(authEntry.privileges, ",");
  232. output << ":" << authEntry.last_login;
  233. output << std::endl;
  234. }
  235. if (!fs::safeWriteToFile(path, output.str())) {
  236. infostream << "Failed to write " << path << std::endl;
  237. return false;
  238. }
  239. return true;
  240. }