networking.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. var logging = require("./logging");
  2. var request = require("request");
  3. var config = require("./config");
  4. var fs = require("fs");
  5. var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
  6. var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
  7. var capes_url = "https://skins.minecraft.net/MinecraftCloaks/";
  8. var mojang_urls = [skins_url, capes_url];
  9. var exp = {};
  10. function extract_url(profile, property) {
  11. var url = null;
  12. if (profile && profile.properties) {
  13. profile.properties.forEach(function(prop) {
  14. if (prop.name === "textures") {
  15. var json = new Buffer(prop.value, "base64").toString();
  16. var props = JSON.parse(json);
  17. url = props && props.textures && props.textures[property] && props.textures[property].url || null;
  18. }
  19. });
  20. }
  21. return url;
  22. }
  23. // exracts the skin url of a +profile+ object
  24. // returns null when no url found (user has no skin)
  25. exp.extract_skin_url = function(profile) {
  26. return extract_url(profile, 'SKIN');
  27. };
  28. // exracts the cape url of a +profile+ object
  29. // returns null when no url found (user has no cape)
  30. exp.extract_cape_url = function(profile) {
  31. return extract_url(profile, 'CAPE');
  32. };
  33. // makes a GET request to the +url+
  34. // +options+ hash includes various options for
  35. // encoding and timeouts, defaults are already
  36. // specified. +callback+ contains the body, response,
  37. // and error buffer. get_from helper method is available
  38. exp.get_from_options = function(rid, url, options, callback) {
  39. request.get({
  40. url: url,
  41. headers: {
  42. "User-Agent": "https://crafatar.com"
  43. },
  44. timeout: (options.timeout || config.http_timeout),
  45. encoding: (options.encoding || null),
  46. followRedirect: (options.folow_redirect || false),
  47. maxAttempts: (options.max_attempts || 2)
  48. }, function(error, response, body) {
  49. // 200 or 301 depending on content type
  50. if (!error && (response.statusCode === 200 || response.statusCode === 301)) {
  51. // response received successfully
  52. logging.log(rid + url + " url received");
  53. callback(body, response, null);
  54. } else if (error) {
  55. callback(body || null, response, error);
  56. } else if (response.statusCode === 404 || response.statusCode === 204) {
  57. // page does not exist
  58. logging.log(rid + url + " url does not exist");
  59. callback(null, response, null);
  60. } else if (response.statusCode === 429) {
  61. // Too Many Requests exception - code 429
  62. logging.warn(rid + url + " Too many requests");
  63. callback(body || null, response, error);
  64. } else {
  65. logging.error(rid + url + " Unknown error:");
  66. logging.error(rid + JSON.stringify(response));
  67. callback(body || null, response, error);
  68. }
  69. });
  70. };
  71. // helper method for get_from_options, no options required
  72. exp.get_from = function(rid, url, callback) {
  73. exp.get_from_options(rid, url, {}, function(body, response, err) {
  74. callback(body, response, err);
  75. });
  76. };
  77. // make a request to skins.miencraft.net
  78. // the skin url is taken from the HTTP redirect
  79. // type reference is above
  80. exp.get_username_url = function(rid, name, type, callback) {
  81. console.log(mojang_urls[type])
  82. exp.get_from(rid, mojang_urls[type] + name + ".png", function(body, response, err) {
  83. if (!err) {
  84. callback(err, response ? (response.statusCode === 404 ? null : response.headers.location) : null);
  85. } else {
  86. callback(err, null);
  87. }
  88. });
  89. };
  90. // gets the URL for a skin/cape from the profile
  91. // +type+ specifies which to retrieve
  92. exp.get_uuid_url = function(profile, type, callback) {
  93. var url = null;
  94. if (type === 0) {
  95. url = exp.extract_skin_url(profile);
  96. } else if (type === 1) {
  97. url = exp.extract_cape_url(profile);
  98. }
  99. callback(url || null);
  100. };
  101. // make a request to sessionserver
  102. // profile is returned as json
  103. exp.get_profile = function(rid, uuid, callback) {
  104. if (!uuid) {
  105. callback(null, null);
  106. } else {
  107. exp.get_from_options(rid, session_url + uuid, { encoding: "utf8" }, function(body, response, err) {
  108. callback(err || null, (body !== null ? JSON.parse(body) : null));
  109. });
  110. }
  111. };
  112. // +userId+ is likely a username and if so
  113. // +userId+ is used to get the url, otherwise
  114. // +profile+ will be used to get the url
  115. exp.get_skin_url = function(rid, userId, profile, callback) {
  116. get_url(rid, userId, profile, 0, function(url) {
  117. callback(url);
  118. });
  119. };
  120. // +userId+ is likely a username and if so
  121. // +userId+ is used to get the url, otherwise
  122. // +profile+ will be used to get the url
  123. exp.get_cape_url = function(rid, userId, profile, callback) {
  124. get_url(rid, userId, profile, 1, function(url) {
  125. callback(url);
  126. });
  127. };
  128. function get_url(rid, userId, profile, type, callback) {
  129. if (userId.length <= 16) {
  130. //username
  131. exp.get_username_url(rid, userId, type, function(err, url) {
  132. callback(url || null);
  133. });
  134. } else {
  135. exp.get_uuid_url(profile, type, function(url) {
  136. callback(url || null);
  137. });
  138. }
  139. }
  140. exp.save_texture = function(rid, hash, outpath, callback) {
  141. if (hash) {
  142. var textureurl = "http://textures.minecraft.net/texture/" + hash;
  143. exp.get_from(rid, textureurl, function(img, response, err) {
  144. if (err) {
  145. logging.error(rid + "error while downloading texture");
  146. callback(err, response, null);
  147. } else {
  148. fs.writeFile(outpath, img, "binary", function(err) {
  149. if (err) {
  150. logging.log(rid + "error: " + err.stack);
  151. }
  152. callback(err, response, img);
  153. });
  154. }
  155. });
  156. } else {
  157. callback(null, null, null);
  158. }
  159. };
  160. module.exports = exp;