Przeglądaj źródła

proper handling of steve/alex

it's more complex than just even/odd UUID
jomo 10 lat temu
rodzic
commit
9c8df06c6b
2 zmienionych plików z 60 dodań i 19 usunięć
  1. 16 5
      modules/skins.js
  2. 44 14
      test/test.js

+ 16 - 5
modules/skins.js

@@ -84,12 +84,23 @@ exp.resize_img = function(inname, size, callback) {
   });
   });
 };
 };
 
 
-// returns "alex" or "steve" calculated by the +userId+
-exp.default_skin = function(userId) {
-  if (Number("0x" + userId[31]) % 2 === 0) {
-    return "alex";
-  } else {
+// returns "alex" or "steve" calculated by the +uuid+
+exp.default_skin = function(uuid) {
+  if (uuid.length <= 16) {
+    // we can't get the
     return "steve";
     return "steve";
+  } else {
+    // great thanks to Minecrell for research into Minecraft and Java's UUID hashing!
+    // https://git.io/xJpV
+    // MC uses `uuid.hashCode() & 1` for alex
+    // that can be compacted to counting the LSBs of every 4th byte in the UUID
+    // an odd sum means alex, an even sum means steve
+    // XOR-ing all the LSBs gives us 1 for alex and 0 for steve
+    var lsbs_even = parseInt(uuid[07], 16) ^
+                    parseInt(uuid[15], 16) ^
+                    parseInt(uuid[23], 16) ^
+                    parseInt(uuid[31], 16);
+      return lsbs_even ? "alex" : "steve";
   }
   }
 };
 };
 
 

+ 44 - 14
test/test.js

@@ -26,6 +26,30 @@ var names = fs.readFileSync("test/usernames.txt").toString().split(/\r?\n/);
 var uuid = uuids[Math.round(Math.random() * (uuids.length - 1))];
 var uuid = uuids[Math.round(Math.random() * (uuids.length - 1))];
 var name = names[Math.round(Math.random() * (names.length - 1))];
 var name = names[Math.round(Math.random() * (names.length - 1))];
 
 
+
+// Let's hope these will never be assigned
+var steve_ids = [
+  "fffffff0"+"fffffff0"+"fffffff0"+"fffffff0",
+  "fffffff0"+"fffffff0"+"fffffff1"+"fffffff1",
+  "fffffff0"+"fffffff1"+"fffffff0"+"fffffff1",
+  "fffffff0"+"fffffff1"+"fffffff1"+"fffffff0",
+  "fffffff1"+"fffffff0"+"fffffff0"+"fffffff1",
+  "fffffff1"+"fffffff0"+"fffffff1"+"fffffff0",
+  "fffffff1"+"fffffff1"+"fffffff0"+"fffffff0",
+  "fffffff1"+"fffffff1"+"fffffff1"+"fffffff1",
+];
+// Let's hope these will never be assigned
+var alex_ids = [
+  "fffffff0"+"fffffff0"+"fffffff0"+"fffffff1",
+  "fffffff0"+"fffffff0"+"fffffff1"+"fffffff0",
+  "fffffff0"+"fffffff1"+"fffffff0"+"fffffff0",
+  "fffffff0"+"fffffff1"+"fffffff1"+"fffffff1",
+  "fffffff1"+"fffffff0"+"fffffff0"+"fffffff0",
+  "fffffff1"+"fffffff0"+"fffffff1"+"fffffff1",
+  "fffffff1"+"fffffff1"+"fffffff0"+"fffffff1",
+  "fffffff1"+"fffffff1"+"fffffff1"+"fffffff0",
+];
+
 var rid = "TestReqID: ";
 var rid = "TestReqID: ";
 
 
 function getRandomInt(min, max) {
 function getRandomInt(min, max) {
@@ -107,13 +131,9 @@ describe("Crafatar", function() {
     });
     });
   });
   });
   describe("Avatar", function() {
   describe("Avatar", function() {
-    // profile "Alex" - hoping it'll never have a skin
-    var alex_uuid = "ec561538f3fd461daff5086b22154bce";
-    // profile "Steven" (Steve doesn't exist) - hoping it'll never have a skin
-    var steven_uuid = "b8ffc3d37dbf48278f69475f6690aabd";
-
     it("uuid's account should exist, but skin should not", function(done) {
     it("uuid's account should exist, but skin should not", function(done) {
-      networking.get_profile(rid, alex_uuid, function(err, profile) {
+      // profile "Alex" - hoping it'll never have a skin
+      networking.get_profile(rid, "ec561538f3fd461daff5086b22154bce", function(err, profile) {
         assert.notStrictEqual(profile, null);
         assert.notStrictEqual(profile, null);
         networking.get_uuid_url(profile, 1, function(url) {
         networking.get_uuid_url(profile, 1, function(url) {
           assert.strictEqual(url, null);
           assert.strictEqual(url, null);
@@ -121,14 +141,24 @@ describe("Crafatar", function() {
         });
         });
       });
       });
     });
     });
-    it("odd UUID should default to Alex", function(done) {
-      assert.strictEqual(skins.default_skin(alex_uuid), "alex");
-      done();
-    });
-    it("even UUID should default to Steve", function(done) {
-      assert.strictEqual(skins.default_skin(steven_uuid), "steve");
-      done();
-    });
+    for (var a in alex_ids) {
+      var alex_id = alex_ids[a];
+      (function(alex_id) {
+        it("UUID " + alex_id + " should default to Alex", function(done) {
+          assert.strictEqual(skins.default_skin(alex_id), "alex");
+          done();
+        });
+      })(alex_id);
+    }
+    for (var s in steve_ids) {
+      var steve_id = steve_ids[s];
+      (function(steve_id) {
+        it("UUID " + steve_id + " should default to Steve", function(done) {
+          assert.strictEqual(skins.default_skin(steve_id), "steve");
+          done();
+        });
+      })(steve_id);
+    }
   });
   });
   describe("Errors", function() {
   describe("Errors", function() {
     it("should time out on uuid info download", function(done) {
     it("should time out on uuid info download", function(done) {