networking.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. var logging = require('./logging');
  2. var request = require('request');
  3. var config = require('./config');
  4. var skins = require('./skins');
  5. var fs = require("fs");
  6. var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
  7. var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
  8. // exracts the skin url of a +profile+ object
  9. // returns null when no url found (user has no skin)
  10. function extract_skin_url(profile) {
  11. var url = null;
  12. if (profile && profile.properties) {
  13. profile.properties.forEach(function(prop) {
  14. if (prop.name == 'textures') {
  15. var json = Buffer(prop.value, 'base64').toString();
  16. var props = JSON.parse(json);
  17. url = props && props.textures && props.textures.SKIN && props.textures.SKIN.url || null;
  18. }
  19. });
  20. }
  21. return url;
  22. }
  23. // make a request to skins.miencraft.net
  24. // the skin url is taken from the HTTP redirect
  25. var get_username_url = function(name, callback) {
  26. request.get({
  27. url: skins_url + name + ".png",
  28. timeout: config.http_timeout,
  29. followRedirect: false
  30. }, function(error, response, body) {
  31. if (!error && response.statusCode == 301) {
  32. // skin_url received successfully
  33. logging.log(name + " skin url received");
  34. callback(null, response.headers.location);
  35. } else if (error) {
  36. callback(error, null);
  37. } else if (response.statusCode == 404) {
  38. // skin doesn't exist
  39. logging.log(name + " has no skin");
  40. callback(0, null);
  41. } else if (response.statusCode == 429) {
  42. // Too Many Requests
  43. // Never got this, seems like skins aren't limited
  44. logging.warn(name + " Too many requests");
  45. logging.warn(body);
  46. callback(null, null);
  47. } else {
  48. logging.error(name + " Unknown error:");
  49. logging.error(response);
  50. logging.error(body);
  51. callback(null, null);
  52. }
  53. });
  54. };
  55. // make a request to sessionserver
  56. // the skin_url is taken from the profile
  57. var get_uuid_url = function(uuid, callback) {
  58. request.get({
  59. url: session_url + uuid,
  60. timeout: config.http_timeout // ms
  61. }, function (error, response, body) {
  62. if (!error && response.statusCode == 200) {
  63. // profile downloaded successfully
  64. logging.log(uuid + " profile downloaded");
  65. callback(null, extract_skin_url(JSON.parse(body)));
  66. } else if (error) {
  67. callback(error, null);
  68. } else if (response.statusCode == 204 || response.statusCode == 404) {
  69. // we get 204 No Content when UUID doesn't exist (including 404 in case they change that)
  70. logging.log(uuid + " uuid does not exist");
  71. callback(0, null);
  72. } else if (response.statusCode == 429) {
  73. // Too Many Requests
  74. logging.warn(uuid + " Too many requests");
  75. logging.warn(body);
  76. callback(null, null);
  77. } else {
  78. logging.error(uuid + " Unknown error:");
  79. logging.error(response);
  80. logging.error(body);
  81. callback(null, null);
  82. }
  83. });
  84. };
  85. var exp = {};
  86. // download skin_url for +uuid+ (name or uuid)
  87. // callback contains error, skin_url
  88. exp.get_skin_url = function(uuid, callback) {
  89. if (uuid.length <= 16) {
  90. get_username_url(uuid, function(err, url) {
  91. callback(err, url);
  92. });
  93. } else {
  94. get_uuid_url(uuid, function(err, url) {
  95. callback(err, url);
  96. });
  97. }
  98. };
  99. // downloads skin file from +url+
  100. // stores face image as +facename+
  101. // stores helm image as +helmname+
  102. // callback contains error
  103. exp.skin_file = function(url, facename, helmname, callback) {
  104. if (fs.existsSync(facename) && fs.existsSync(facename)) {
  105. logging.log("Images already exist, not downloading.");
  106. callback(null);
  107. return;
  108. }
  109. request.get({
  110. url: url,
  111. encoding: null, // encoding must be null so we get a buffer
  112. timeout: config.http_timeout // ms
  113. }, function (error, response, body) {
  114. if (!error && response.statusCode == 200) {
  115. // skin downloaded successfully
  116. logging.log(url + " skin downloaded");
  117. skins.extract_face(body, facename, function(err) {
  118. if (err) {
  119. callback(err);
  120. } else {
  121. logging.log(facename + " face extracted");
  122. skins.extract_helm(facename, body, helmname, function(err) {
  123. logging.log(helmname + " helm extracted.");
  124. callback(err);
  125. });
  126. }
  127. });
  128. } else {
  129. if (error) {
  130. logging.error("Error downloading '" + url + "': " + error);
  131. } else if (response.statusCode == 404) {
  132. logging.warn("texture not found (404): " + url);
  133. } else if (response.statusCode == 429) {
  134. // Too Many Requests
  135. // Never got this, seems like textures aren't limited
  136. logging.warn("too many requests for " + url);
  137. logging.warn(body);
  138. } else {
  139. logging.error("unknown error for " + url);
  140. logging.error(response);
  141. logging.error(body);
  142. error = "unknown error"; // Error needs to be set, otherwise null in callback
  143. }
  144. callback(error);
  145. }
  146. });
  147. };
  148. module.exports = exp;