| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 | 
							- var http_code = require("http").STATUS_CODES;
 
- var logging = require("./logging");
 
- var request = require("request");
 
- var config = require("../config");
 
- var skins = require("./skins");
 
- require("./object-patch");
 
- var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/";
 
- var skins_url = "https://skins.minecraft.net/MinecraftSkins/";
 
- var capes_url = "https://skins.minecraft.net/MinecraftCloaks/";
 
- var textures_url = "http://textures.minecraft.net/texture/";
 
- var mojang_urls = [skins_url, capes_url];
 
- var exp = {};
 
- // helper method that calls `get_username_url` or `get_uuid_info` based on the +usedId+
 
- // +userId+ is used for usernames, while +profile+ is used for UUIDs
 
- // callback: error, url, slim
 
- function get_info(rid, userId, profile, type, callback) {
 
-   if (userId.length <= 16) {
 
-     // username
 
-     exp.get_username_url(rid, userId, type, function(err, url) {
 
-       callback(err, url || null, undefined);
 
-     });
 
-   } else {
 
-     exp.get_uuid_info(profile, type, function(url, slim) {
 
-       callback(null, url || null, slim);
 
-     });
 
-   }
 
- }
 
- // performs a GET request to the +url+
 
- // +options+ object includes these options:
 
- //   encoding (string), default is to return a buffer
 
- // callback: the body, response,
 
- // and error buffer. get_from helper method is available
 
- exp.get_from_options = function(rid, url, options, callback) {
 
-   request.get({
 
-     url: url,
 
-     headers: {
 
-       "User-Agent": "https://crafatar.com"
 
-     },
 
-     timeout: config.server.http_timeout,
 
-     followRedirect: false,
 
-     encoding: options.encoding || null,
 
-   }, function(error, response, body) {
 
-     // log url + code + description
 
-     var code = response && response.statusCode;
 
-     var logfunc = code && code < 405 ? logging.debug : logging.warn;
 
-     logfunc(rid, url, code || error && error.code, http_code[code]);
 
-     // not necessarily used
 
-     var e = new Error(code);
 
-     e.name = "HTTP";
 
-     e.code = "HTTPERROR";
 
-     switch (code) {
 
-       case 200:
 
-       case 301:
 
-       case 302: // never seen, but mojang might use it in future
 
-       case 307: // never seen, but mojang might use it in future
 
-       case 308: // never seen, but mojang might use it in future
 
-         // these are okay
 
-         break;
 
-       case 204: // no content, used like 404 by mojang. making sure it really has no content
 
-       case 404:
 
-         // can be cached as null
 
-         body = null;
 
-         break;
 
-       case 429: // this shouldn't usually happen, but occasionally does
 
-       case 500:
 
-       case 503:
 
-       case 504:
 
-         // we don't want to cache this
 
-         error = error || e;
 
-         body = null;
 
-         break;
 
-       default:
 
-         if (!error) {
 
-           // Probably 500 or the likes
 
-           logging.error(rid, "Unexpected response:", code, body);
 
-         }
 
-         error = error || e;
 
-         body = null;
 
-         break;
 
-     }
 
-     if (body && !body.length) {
 
-       // empty response
 
-       body = null;
 
-     }
 
-     callback(body, response, error);
 
-   });
 
- };
 
- // helper method for get_from_options, no options required
 
- exp.get_from = function(rid, url, callback) {
 
-   exp.get_from_options(rid, url, {}, function(body, response, err) {
 
-     callback(body, response, err);
 
-   });
 
- };
 
- // make a request to skins.miencraft.net
 
- // the skin url is taken from the HTTP redirect
 
- // type reference is above
 
- exp.get_username_url = function(rid, name, type, callback) {
 
-   type = Number(type === "CAPE");
 
-   exp.get_from(rid, mojang_urls[type] + name + ".png", function(body, response, err) {
 
-     if (!err) {
 
-       if (response) {
 
-         callback(err, response.statusCode === 404 ? null : response.headers.location);
 
-       } else {
 
-         callback(err, null);
 
-       }
 
-     } else {
 
-       callback(err, null);
 
-     }
 
-   });
 
- };
 
- // gets the URL for a skin/cape from the profile
 
- // +type+ "SKIN" or "CAPE", specifies which to retrieve
 
- // callback: url, slim
 
- exp.get_uuid_info = function(profile, type, callback) {
 
-   var properties = Object.get(profile, "properties") || [];
 
-   properties.forEach(function(prop) {
 
-     if (prop.name === "textures") {
 
-       var json = new Buffer(prop.value, "base64").toString();
 
-       profile = JSON.parse(json);
 
-     }
 
-   });
 
-   var url = Object.get(profile, "textures." + type + ".url");
 
-   var slim;
 
-   if (type === "SKIN") {
 
-     slim = Object.get(profile, "textures.SKIN.metadata.model") === "slim";
 
-   }
 
-   callback(url || null, !!slim);
 
- };
 
- // make a request to sessionserver for +uuid+
 
- // callback: error, profile
 
- exp.get_profile = function(rid, uuid, callback) {
 
-   if (!uuid) {
 
-     callback(null, null);
 
-   } else {
 
-     exp.get_from_options(rid, session_url + uuid, { encoding: "utf8" }, function(body, response, err) {
 
-       try {
 
-         body = body ? JSON.parse(body) : null;
 
-         callback(err || null, body);
 
-       } catch(e) {
 
-         if (e instanceof SyntaxError) {
 
-           logging.warn(rid, "Failed to parse JSON", e);
 
-           logging.debug(rid, body);
 
-           callback(err || null, null);
 
-         } else {
 
-           throw e;
 
-         }
 
-       }
 
-     });
 
-   }
 
- };
 
- // get the skin URL and type for +userId+
 
- // +profile+ is used if +userId+ is a uuid
 
- // callback: error, url, slim
 
- exp.get_skin_info = function(rid, userId, profile, callback) {
 
-   get_info(rid, userId, profile, "SKIN", callback);
 
- };
 
- // get the cape URL for +userId+
 
- // +profile+ is used if +userId+ is a uuid
 
- exp.get_cape_url = function(rid, userId, profile, callback) {
 
-   get_info(rid, userId, profile, "CAPE", callback);
 
- };
 
- // download the +tex_hash+ image from the texture server
 
- // and save it in the +outpath+ file
 
- // callback: error, response, image buffer
 
- exp.save_texture = function(rid, tex_hash, outpath, callback) {
 
-   if (tex_hash) {
 
-     var textureurl = textures_url + tex_hash;
 
-     exp.get_from(rid, textureurl, function(img, response, err) {
 
-       if (err) {
 
-         callback(err, response, null);
 
-       } else {
 
-         skins.save_image(img, outpath, function(img_err, saved_img) {
 
-           callback(img_err, response, saved_img);
 
-         });
 
-       }
 
-     });
 
-   } else {
 
-     callback(null, null, null);
 
-   }
 
- };
 
- module.exports = exp;
 
 
  |