diff --git a/README.md b/README.md index aacb8068..04d6259d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Just a simple open-source Minecraft skin server write in PHP. [Live demo](https://work.prinzeugen.net/blessing-skin-server/) -![screenshot](https://img.prinzeugen.net/image.php?di=TASP) +![screenshot](https://img.prinzeugen.net/image.php?di=FIQD) Features: ----------- @@ -31,8 +31,13 @@ Add rewrite rules to your nginx.conf: location / { rewrite ^/([^/]*).json$ /get.php?type=json&uname=$1 last; rewrite ^/(skin|cape)/([^/]*).png$ /get.php?type=$1&uname=$2 last; + # Optional + rewrite ^/(usm|csl)/([^/]*).json$ /get.php?type=json&uname=$2&api=$1 last; + rewrite ^/(usm|csl)/textures/(.*)$ /textures/$2 last; } ``` +You can also use optional rewrite rules to support both CustomSkinLoader API & UniSkinAPI. (Access `example.com/(usm|csl)/username.json` to get json for CustomSkinLoader API or UniSkinAPI) + If you installed the skin server to subdirectory, be careful of your `location`. Now you can access `http://example.com/username.json` to get your json profile. After uploading skins, you can also access `http://example.com/skin/username.png` for skin image or `http://example.com/cape/username.png` for cape. diff --git a/admin/admin_ajax.php b/admin/admin_ajax.php index af1ce3c2..070cdc5c 100644 --- a/admin/admin_ajax.php +++ b/admin/admin_ajax.php @@ -3,12 +3,11 @@ * @Author: prpr * @Date: 2016-02-04 13:53:55 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 17:14:06 + * @Last Modified time: 2016-02-04 18:42:22 */ session_start(); $dir = dirname(dirname(__FILE__)); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; if(isset($_COOKIE['uname']) && isset($_COOKIE['token'])) { $_SESSION['uname'] = $_COOKIE['uname']; @@ -61,6 +60,16 @@ if (isset($_GET['action'])) { $user->unRegister(); $json['errno'] = 0; $json['msg'] = "Account successfully deleted."; + } else if ($action == "model") { + if (isset($_POST['model']) && $_POST['model'] == 'slim' || $_POST['model'] == 'default') { + $user->setPreference($_POST['model']); + $json['errno'] = 0; + $json['msg'] = "Model preference of ".$_GET['uname']." changed to ".$_POST['model']." successfully."; + } else { + utils::raise(1, 'Illegal parameters'); + } + } else { + utils::raise(1, 'Illegal parameters'); } } diff --git a/admin/index.php b/admin/index.php index 18a02534..d1d0ede8 100644 --- a/admin/index.php +++ b/admin/index.php @@ -3,13 +3,12 @@ * @Author: prpr * @Date: 2016-02-03 14:39:50 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 17:32:11 + * @Last Modified time: 2016-02-04 23:45:06 */ session_start(); $dir = dirname(dirname(__FILE__)); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; if(isset($_COOKIE['uname']) && isset($_COOKIE['token'])) { $_SESSION['uname'] = $_COOKIE['uname']; @@ -52,7 +51,7 @@ if (isset($_SESSION['uname'])) { Profile
  • - Welcome, ! + Welcome, ! | Log out?
  • @@ -88,12 +87,14 @@ if (isset($_SESSION['uname'])) { '; ?> - Skin - Cape + Skin + Cape + Model + () - Password - Delete + Password + Delete @@ -101,13 +102,10 @@ if (isset($_SESSION['uname'])) {
    - - + diff --git a/admin/install.php b/admin/install.php index a2da67f5..5183e50f 100644 --- a/admin/install.php +++ b/admin/install.php @@ -3,14 +3,13 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-03 15:51:27 + * @Last Modified time: 2016-02-04 18:42:51 * * Create tables automatically */ $dir = dirname(dirname(__FILE__)); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; echo ""; diff --git a/ajax.php b/ajax.php index 685dea31..b1da2cea 100644 --- a/ajax.php +++ b/ajax.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-03 21:10:24 + * @Last Modified time: 2016-02-04 18:48:30 * * - login, register, logout * - upload, change, delete @@ -11,16 +11,14 @@ * All ajax requests will be handled here */ +session_start(); header('Access-Control-Allow-Origin: *'); header('Content-type: application/json'); $dir = dirname(__FILE__); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; database::checkConfig(); -session_start(); - if (isset($_POST['uname'])) { $user = new user($_POST['uname']); } else { diff --git a/assets/css/profile.style.css b/assets/css/profile.style.css index e7e0eddc..133dc68c 100644 --- a/assets/css/profile.style.css +++ b/assets/css/profile.style.css @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-02-03 17:11:53 * @Last Modified by: prpr -* @Last Modified time: 2016-02-03 17:18:56 +* @Last Modified time: 2016-02-04 22:50:43 */ .pure-form > *, .pure-button { width: 100%; @@ -20,48 +20,6 @@ body { color: #444; } -@media screen and (max-width: 550px) { - .pure-g:first-child { - margin-top: 100px !important; - } -} -.pure-g:first-child { - margin-top: 75px; -} -.panel-default { - border-color: #ddd!important; -} -.panel-danger { - border-color: #ebccd1!important; -} -.panel { - background-color: #fff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05); - box-shadow: 0 1px 1px rgba(0,0,0,.05); - width: 90%; - margin: 0 auto 20px; -} -.panel-danger>.panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.panel-default>.panel-heading { - color: #333; - background-color: #f5f5f5; - border-color: #ddd; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel-body { - padding: 10px 15px 15px; -} .home-menu-blur { position: absolute; @@ -94,7 +52,3 @@ body { url("../images/bg_stone.png"); background-repeat: repeat; } -.pure-button-error { - background: rgb(202, 60, 60); - color: #fff; -} diff --git a/assets/css/style.css b/assets/css/style.css index 274b7b07..07cc93ce 100755 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-01-21 07:57:38 * @Last Modified by: prpr -* @Last Modified time: 2016-02-03 23:20:04 +* @Last Modified time: 2016-02-04 23:15:08 */ @import url(https://fonts.googleapis.com/css?family=Ubuntu); @@ -53,9 +53,16 @@ p { .pure-menu-selected { font-weight: bold; } -.pure-menu-link { +.pure-menu-item { color: #5e5e5e !important; } +.pure-menu-link { + display: inline-block; + color: #5e5e5e !important; + font-size: 15px; + cursor: pointer; + padding: .5em .5em; +} .pure-menu-link:hover, .pure-menu-link:focus { background: none; @@ -65,7 +72,10 @@ p { .pure-button { margin: .5em 1em; } - +.pure-button-error { + background: rgb(202, 60, 60); + color: #fff; +} .container { width: 100%; height: 100%; @@ -112,5 +122,45 @@ p { } -@media (min-width: 78em) { +.panel-default { + border-color: #ddd!important; +} +.panel-danger { + border-color: #ebccd1!important; +} +.panel { + background-color: #fff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05); + box-shadow: 0 1px 1px rgba(0,0,0,.05); + width: 90%; + margin: 0 auto 20px; +} +.panel-danger>.panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-default>.panel-heading { + color: #333; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel-body { + padding: 10px 15px 15px; +} +.pure-g:first-child { + margin-top: 75px; +} +@media screen and (max-width: 40em) { + .pure-g:first-child { + margin-top: 100px; + } } diff --git a/assets/css/user.style.css b/assets/css/user.style.css index b4528f84..627c9f81 100644 --- a/assets/css/user.style.css +++ b/assets/css/user.style.css @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-01-21 19:12:06 * @Last Modified by: prpr -* @Last Modified time: 2016-02-04 12:56:15 +* @Last Modified time: 2016-02-04 22:57:13 */ .home-menu-blur { @@ -32,6 +32,7 @@ } body { + color: #444; background-image: url("../images/bg_stone.png"); background-repeat: repeat; @@ -59,8 +60,7 @@ body { } #canvas3d { - margin-top: 8%; - margin-left: 20%; + margin: 0 auto; display: block; } @@ -81,9 +81,22 @@ button { } span { padding: .5em .5em; - color: #5e5e5e; - margin-top: 0.1em; + display: inline !important; } .alert { margin: 20px 0 0; } +input[type=radio] { + margin: 20px 0 0; +} +.operations { + display: inline; + float: right; +} +.operations > span:hover { + color: #555; + cursor: pointer; +} +.container { + position: initial !important; +} diff --git a/assets/js/admin.utils.js b/assets/js/admin.utils.js index abc01778..1116f79e 100644 --- a/assets/js/admin.utils.js +++ b/assets/js/admin.utils.js @@ -2,48 +2,47 @@ * @Author: prpr * @Date: 2016-02-04 16:48:42 * @Last Modified by: prpr -* @Last Modified time: 2016-02-04 17:09:20 +* @Last Modified time: 2016-02-04 18:27:44 */ 'use strict'; -function showUpload(uname, type) { +function uploadTexture(uname, type) { var ply = new Ply({ - el: '

    Upload new '+type+':

    ', + el: '

    Upload new '+type+':

    '+ + ''+ + '', effect: "fade", - onaction: function(){ upload(uname, type, $('#file').get(0).files[0]); }, + onaction: function(){ + var form_data = new FormData(); + var file = $('#file').get(0).files[0]; + if (file) { + form_data.append('file', file); + $.ajax({ + type: 'POST', + contentType: false, + url: 'admin_ajax.php?action=upload&type='+type+'&uname='+uname, + dataType: "json", + data: form_data, + processData: false, + success: function(json) { + if (json.errno == 0) { + showAlert("Successfully uploaded.", function(){ + location.reload(); + }); + } else { + showAlert("Error when uploading cape:\n" + json.msg); + } + } + }); + } + }, }); ply.open(); } -function upload(uname, type, file){ - var form_data = new FormData(); - if (file) { - form_data.append('file', file); - $.ajax({ - type: 'POST', - contentType: false, - url: 'admin_ajax.php?action=upload&type='+type+'&uname='+uname, - dataType: "json", - data: form_data, - processData: false, - success: function(json) { - if (json.errno == 0) { - showAlert("Successfully uploaded."); - $('#'+uname+'_'+type).attr('src', 'http://skin.fuck.io/'+type+'/'+uname+'.png?t='+Math.random()); - } else { - showAlert("Error when uploading cape:\n" + json.msg); - } - } - }); - } -} -function showAlert(msg) { - Ply.dialog("alert", msg); -} - -function showChange(uname) { +function changePasswd(uname) { Ply.dialog("prompt", { title: "Type in "+uname+"'s new password", form: { passwd: "New Password" } @@ -65,7 +64,7 @@ function showChange(uname) { }); } -function showDelete(uname) { +function deleteAccount(uname) { Ply.dialog("prompt", { title: "Are you sure to delete "+uname+"?", }).done(function(ui){ @@ -75,7 +74,9 @@ function showDelete(uname) { dataType: "json", success: function(json) { if (json.errno == 0) { - showAlert(json.msg); + showAlert(json.msg, function(){ + location.reload(); + }); } else { showAlert(json.msg); } @@ -83,3 +84,31 @@ function showDelete(uname) { }); }); } + +function changeModel(uname) { + Ply.dialog("prompt", { + title: "Change "+uname+"'s model prefrence:", + form: { text: "Type in `slim` or `default`" } + }).done(function(ui){ + var model = ui.data.text; + if (model == 'slim'| model == 'default') { + $.ajax({ + type: "POST", + url: "admin_ajax.php?action=model&uname="+uname, + data: { "model": ui.data.text }, + dataType: "json", + success: function(json) { + if (json.errno == 0) { + showAlert(json.msg, function(){ + location.reload(); + }); + } else { + showAlert(json.msg); + } + } + }); + } else { + showAlert('Only `slim` or `default` is valid.'); + } + }); +} diff --git a/assets/js/user.utils.js b/assets/js/user.utils.js index d2a9be52..d673f147 100644 --- a/assets/js/user.utils.js +++ b/assets/js/user.utils.js @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-01-21 13:56:40 * @Last Modified by: prpr -* @Last Modified time: 2016-02-03 19:58:45 +* @Last Modified time: 2016-02-04 23:38:39 */ 'use strict'; @@ -43,39 +43,34 @@ var handleFiles = function (files, type) { } }; -var canvas = MSP.get3dSkinCanvas(500, 500); -$("#skinpreview").append($(canvas).prop("id", "canvas3d")); +if ($(window).width() < 600) { + var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width()); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); +} else { + var canvas = MSP.get3dSkinCanvas(400, 400); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); +} + +$(window).resize(function(){ + if ($(document).height() <= $(window).height() || $(window).width() < 600) { + var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width()); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); + } else { + var canvas = MSP.get3dSkinCanvas(400, 400); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); + } +}); $("[title='Movements']").click(function(){ - if (MSP.getStatus("movements")) { - MSP.setStatus("movements", false); - } else { - MSP.setStatus("movements", true); - } + MSP.setStatus("movements", !MSP.getStatus("movements")); }); $("[title='Running']").click(function(){ - if (MSP.getStatus("running")) { - MSP.setStatus("running", false); - } else { - MSP.setStatus("running", true); - } + MSP.setStatus("running", !MSP.getStatus("running")); }); $("[title='Rotation']").click(function(){ - if (MSP.getStatus("rotation")) { - MSP.setStatus("rotation", false); - } else { - MSP.setStatus("rotation", true); - } -}); - -$("#logout").click(function(){ - logout(function(json){ - showAlert(json.msg + " Successfully logged out.", function(){ - window.location = "../index.php"; - }); - }); + MSP.setStatus("rotation", !MSP.getStatus("rotation")); }); $("#upload").click(function(){ @@ -117,7 +112,6 @@ $("#upload").click(function(){ } else { showMsg("alert-warning", "No input file selected"); } - }); diff --git a/assets/js/utils.js b/assets/js/utils.js index b0d0f8c7..b666010a 100644 --- a/assets/js/utils.js +++ b/assets/js/utils.js @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-02-03 18:23:21 * @Last Modified by: prpr -* @Last Modified time: 2016-02-03 19:19:14 +* @Last Modified time: 2016-02-04 23:02:46 */ 'use strict'; @@ -30,3 +30,11 @@ function logout(callback) { } }); } + +$("#logout").click(function(){ + logout(function(json){ + showAlert(json.msg + " Successfully logged out.", function(){ + window.location = "../index.php"; + }); + }); +}); diff --git a/config.php b/config.php index 1257d022..e0c24ec4 100644 --- a/config.php +++ b/config.php @@ -17,5 +17,5 @@ define('SALT', '9tvsh55d*s'); /* Max amount of accounts per IP */ define('REGS_PER_IP', 2); -/* Do not change this */ -define('DIR', dirname(__FILE__)); +/* Which API to use, 0 for CustomSkinLoader API, 1 for UniSkinAPI */ +define('API_TYPE', 0); diff --git a/get.php b/get.php index 36bb8064..38bbbad4 100644 --- a/get.php +++ b/get.php @@ -3,17 +3,18 @@ * @Author: prpr * @Date: 2016-02-02 20:56:42 * @Last Modified by: prpr - * @Last Modified time: 2016-02-03 13:37:33 + * @Last Modified time: 2016-02-04 22:06:20 + * + * All textures requests of legacy link will be handle here. */ $dir = dirname(__FILE__); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; if (isset($_GET['type']) && isset($_GET['uname'])) { $user = new user($_GET['uname']); if (!$user->is_registered) utils::raise(1, 'Non-existent user.'); - + // Cache friendly $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : null; if ($_GET['type'] == "skin" || $_GET['type'] == "cape") { @@ -23,7 +24,11 @@ if (isset($_GET['type']) && isset($_GET['uname'])) { echo $user->getBinaryTexture($_GET['type']); } } else if ($_GET['type'] == "json") { - echo $user->getJsonProfile(); + if (isset($_GET['api'])) { + echo $user->getJsonProfile(($_GET['api'] == 'csl') ? 0 : 1); + } else { + echo $user->getJsonProfile(API_TYPE); + } } else { utils::raise(1, 'Illegal parameters.'); } diff --git a/includes/autoload.inc.php b/includes/autoload.inc.php index 4ad7d385..d125de95 100644 --- a/includes/autoload.inc.php +++ b/includes/autoload.inc.php @@ -3,7 +3,7 @@ * @Author: prpr * @Date: 2016-02-02 21:17:59 * @Last Modified by: prpr - * @Last Modified time: 2016-02-02 21:19:31 + * @Last Modified time: 2016-02-04 18:34:34 */ function __autoload($classname) { @@ -11,3 +11,4 @@ function __autoload($classname) { $filename = "$dir/includes/".$classname.".class.php"; include_once($filename); } +require "$dir/config.php"; diff --git a/includes/user.class.php b/includes/user.class.php index 7f540e7c..f25bb602 100644 --- a/includes/user.class.php +++ b/includes/user.class.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 13:48:48 + * @Last Modified time: 2016-02-04 20:38:42 */ class user @@ -121,15 +121,23 @@ class user return $this->db->select('username', $this->uname)['preference']; } - public function getJsonProfile() { + public function getJsonProfile($api_type) { header('Content-type: application/json'); if ($this->is_registered) { - $json['player_name'] = $this->uname; - $json['last_update'] = $this->getLastModified(); - $preference = $this->getPreference(); - $json['model_preference'] = [$preference]; - $json['skins'][$preference] = $this->getTexture('skin'); - $json['cape'] = $this->getTexture('cape'); + if ($api_type == 0 || $api_type == 1) { + $json[($api_type == 0) ? 'username' : 'player_name'] = $this->uname; + $model = $this->getPreference(); + $sec_model = ($model == 'default') ? 'slim' : 'default'; + if ($api_type == 1) { + $json['last_update'] = $this->getLastModified(); + $json['model_preference'] = [$model, $sec_model]; + } + $json['skins'][$model] = $this->getTexture('skin'); + $json['skins'][$sec_model] = $this->getTexture('skin'); + $json['cape'] = $this->getTexture('cape'); + } else { + utils::raise(-1, 'Configuration error. Non-supported API_TYPE.'); + } } else { $json['errno'] = 1; $json['msg'] = "Non-existent user."; diff --git a/includes/utils.class.php b/includes/utils.class.php index 9623f56f..b416ae7f 100644 --- a/includes/utils.class.php +++ b/includes/utils.class.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 16:20:19 + * @Last Modified time: 2016-02-04 23:43:07 */ class utils @@ -29,9 +29,10 @@ class utils * @return string $hash, sha256 hash of file */ public static function upload($file) { - move_uploaded_file($file["tmp_name"], DIR."/textures/tmp.png"); - $hash = hash_file('sha256', DIR."/textures/tmp.png"); - rename(DIR."/textures/tmp.png", DIR."/textures/".$hash); + $dir = dirname(dirname(__FILE__)); + move_uploaded_file($file["tmp_name"], "$dir/textures/tmp.png"); + $hash = hash_file('sha256', "$dir/textures/tmp.png"); + rename("$dir/textures/tmp.png", "$dir/textures/".$hash); return $hash; } @@ -76,4 +77,3 @@ class utils } } -?> diff --git a/index.php b/index.php index 01711b38..d2f69504 100755 --- a/index.php +++ b/index.php @@ -3,12 +3,12 @@ * @Author: printempw * @Date: 2016-01-17 13:55:20 * @Last Modified by: prpr - * @Last Modified time: 2016-02-03 22:20:07 + * @Last Modified time: 2016-02-04 23:16:26 */ session_start(); $dir = dirname(__FILE__); require "$dir/includes/autoload.inc.php"; -require "$dir/config.php"; + database::checkConfig(); // Auto load cookie value to session if (isset($_COOKIE['uname']) && isset($_COOKIE['token'])) { @@ -17,7 +17,8 @@ if (isset($_COOKIE['uname']) && isset($_COOKIE['token'])) { $_SESSION['uname'] = $_COOKIE['uname']; $_SESSION['token'] = $user->getToken(); } -} ?> +} +?> @@ -39,12 +40,10 @@ if (isset($_COOKIE['uname']) && isset($_COOKIE['token'])) {
    Blessing Skin Server
    @@ -111,10 +110,6 @@ if (isset($_SESSION['uname'])) {
    - -