Merge branch 'upgrade'
84
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
- name: Install pipenv
|
||||
run: pip install pipenv
|
||||
|
||||
- id: cache-pipenv
|
||||
name: Download cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.local/share/virtualenvs
|
||||
key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.cache-pipenv.outputs.cache-hit != 'true'
|
||||
run: pipenv install --deploy --dev
|
||||
|
||||
- name: Build gettext strings
|
||||
run: pipenv run sphinx-build -b gettext source build/locale
|
||||
|
||||
- name: Push and Pull strings from the Crowdin
|
||||
uses: crowdin/github-action@1.1.0
|
||||
# TODO: remove upgrade branch after finishing upgrading process
|
||||
if: contains(fromJson('["refs/heads/master", "refs/heads/upgrade"]'), github.ref)
|
||||
with:
|
||||
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
|
||||
upload_sources: true
|
||||
|
||||
download_translations: true
|
||||
push_translations: false
|
||||
download_language: en # Temporary limit only to English
|
||||
|
||||
- name: Fix permissions to the locale dir
|
||||
run: sudo chown -R $USER:$USER locale
|
||||
|
||||
- name: Build docs
|
||||
run: pipenv run python build-multilang.py
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
retention-days: 7
|
||||
|
||||
Deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: Build
|
||||
# TODO: remove upgrade branch after finishing upgrading process
|
||||
if: contains(fromJson('["refs/heads/master", "refs/heads/upgrade"]'), github.ref)
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- id: download
|
||||
name: Download build artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: build
|
||||
|
||||
- name: Deploy to the GitHub Pages
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: ${{ steps.download.outputs.download-path }}
|
||||
single-commit: true
|
3
.gitignore
vendored
@ -6,3 +6,6 @@
|
||||
|
||||
### venv folder
|
||||
/venv
|
||||
|
||||
### The directory for the locales from the Crowdin
|
||||
/locale
|
||||
|
20
.travis.yml
@ -1,20 +0,0 @@
|
||||
os: linux
|
||||
dist: xenial
|
||||
language: python
|
||||
|
||||
cache: pip
|
||||
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
|
||||
script:
|
||||
- sphinx-build source build
|
||||
|
||||
deploy:
|
||||
provider: pages
|
||||
strategy: git
|
||||
skip_cleanup: true
|
||||
local_dir: ./build
|
||||
token: $GITHUB_TOKEN
|
||||
on:
|
||||
branch: master
|
16
Pipfile
Normal file
@ -0,0 +1,16 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
Sphinx = ">=3.0,<4.0"
|
||||
sphinx-rtd-theme = "~=0.5.1"
|
||||
|
||||
[dev-packages]
|
||||
lxml = ">=4.6.2,<5.0"
|
||||
sphinx-autobuild = ">=2020.09.01"
|
||||
sphinx-intl = ">=2.0,<3.0"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
626
Pipfile.lock
generated
Normal file
@ -0,0 +1,626 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "f276bc0ed2af04e02fbf86b128186f6c4632d643f77c387892d9c775dbfb068f"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
|
||||
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
|
||||
],
|
||||
"version": "==0.7.12"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5",
|
||||
"sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.9.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
|
||||
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
|
||||
],
|
||||
"version": "==2020.12.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af",
|
||||
"sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.16"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.10"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1",
|
||||
"sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
|
||||
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.11.3"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||
"sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
|
||||
"sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
|
||||
"sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
|
||||
"sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
|
||||
"sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
|
||||
"sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||
"sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
|
||||
"sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
|
||||
"sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
|
||||
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
|
||||
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==20.9"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94",
|
||||
"sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
|
||||
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
|
||||
],
|
||||
"version": "==2021.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2",
|
||||
"sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"
|
||||
],
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:672cfcc24b6b69235c97c750cb190a44ecd72696b4452acaf75c2d9cc78ca5ff",
|
||||
"sha256:ef64a814576f46ec7de06adf11b433a0d6049be007fefe7fd0d183d28b581fac"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.5.2"
|
||||
},
|
||||
"sphinx-rtd-theme": {
|
||||
"hashes": [
|
||||
"sha256:eda689eda0c7301a80cf122dad28b1861e5605cbf455558f3775e1e8200e83a5",
|
||||
"sha256:fa6bebd5ab9a73da8e102509a86f3fcc36dec04a0b52ea80e5a033b2aba00113"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"sphinxcontrib-applehelp": {
|
||||
"hashes": [
|
||||
"sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
|
||||
"sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"sphinxcontrib-devhelp": {
|
||||
"hashes": [
|
||||
"sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
|
||||
"sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"sphinxcontrib-htmlhelp": {
|
||||
"hashes": [
|
||||
"sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f",
|
||||
"sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"sphinxcontrib-jsmath": {
|
||||
"hashes": [
|
||||
"sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
|
||||
"sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"sphinxcontrib-qthelp": {
|
||||
"hashes": [
|
||||
"sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
|
||||
"sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"sphinxcontrib-serializinghtml": {
|
||||
"hashes": [
|
||||
"sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc",
|
||||
"sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.1.4"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
|
||||
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.4"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
|
||||
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
|
||||
],
|
||||
"version": "==0.7.12"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5",
|
||||
"sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.9.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
|
||||
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
|
||||
],
|
||||
"version": "==2020.12.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
|
||||
"sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.4.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af",
|
||||
"sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.16"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.10"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1",
|
||||
"sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
|
||||
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.11.3"
|
||||
},
|
||||
"livereload": {
|
||||
"hashes": [
|
||||
"sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"
|
||||
],
|
||||
"version": "==2.6.3"
|
||||
},
|
||||
"lxml": {
|
||||
"hashes": [
|
||||
"sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d",
|
||||
"sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37",
|
||||
"sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01",
|
||||
"sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2",
|
||||
"sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644",
|
||||
"sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75",
|
||||
"sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80",
|
||||
"sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2",
|
||||
"sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780",
|
||||
"sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98",
|
||||
"sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308",
|
||||
"sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf",
|
||||
"sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388",
|
||||
"sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d",
|
||||
"sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3",
|
||||
"sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8",
|
||||
"sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af",
|
||||
"sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2",
|
||||
"sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e",
|
||||
"sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939",
|
||||
"sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03",
|
||||
"sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d",
|
||||
"sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a",
|
||||
"sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5",
|
||||
"sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a",
|
||||
"sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711",
|
||||
"sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf",
|
||||
"sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089",
|
||||
"sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505",
|
||||
"sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b",
|
||||
"sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f",
|
||||
"sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc",
|
||||
"sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e",
|
||||
"sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931",
|
||||
"sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc",
|
||||
"sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe",
|
||||
"sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.6.2"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||
"sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
|
||||
"sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
|
||||
"sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
|
||||
"sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
|
||||
"sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
|
||||
"sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||
"sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
|
||||
"sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
|
||||
"sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
|
||||
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
|
||||
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==20.9"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94",
|
||||
"sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
|
||||
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
|
||||
],
|
||||
"version": "==2021.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
|
||||
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2",
|
||||
"sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"
|
||||
],
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:672cfcc24b6b69235c97c750cb190a44ecd72696b4452acaf75c2d9cc78ca5ff",
|
||||
"sha256:ef64a814576f46ec7de06adf11b433a0d6049be007fefe7fd0d183d28b581fac"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.5.2"
|
||||
},
|
||||
"sphinx-autobuild": {
|
||||
"hashes": [
|
||||
"sha256:8fe8cbfdb75db04475232f05187c776f46f6e9e04cacf1e49ce81bdac649ccac",
|
||||
"sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2021.3.14"
|
||||
},
|
||||
"sphinx-intl": {
|
||||
"hashes": [
|
||||
"sha256:2ff97cba0e4e43249e339a3c29dd2f5b63c25ce794050aabca320ad95f5c5b55",
|
||||
"sha256:b25a6ec169347909e8d983eefe2d8adecb3edc2f27760db79b965c69950638b4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"sphinxcontrib-applehelp": {
|
||||
"hashes": [
|
||||
"sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
|
||||
"sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"sphinxcontrib-devhelp": {
|
||||
"hashes": [
|
||||
"sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
|
||||
"sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"sphinxcontrib-htmlhelp": {
|
||||
"hashes": [
|
||||
"sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f",
|
||||
"sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"sphinxcontrib-jsmath": {
|
||||
"hashes": [
|
||||
"sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
|
||||
"sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"sphinxcontrib-qthelp": {
|
||||
"hashes": [
|
||||
"sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
|
||||
"sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"sphinxcontrib-serializinghtml": {
|
||||
"hashes": [
|
||||
"sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc",
|
||||
"sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.1.4"
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb",
|
||||
"sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c",
|
||||
"sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288",
|
||||
"sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95",
|
||||
"sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558",
|
||||
"sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe",
|
||||
"sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791",
|
||||
"sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d",
|
||||
"sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326",
|
||||
"sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b",
|
||||
"sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4",
|
||||
"sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c",
|
||||
"sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910",
|
||||
"sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5",
|
||||
"sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c",
|
||||
"sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0",
|
||||
"sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675",
|
||||
"sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd",
|
||||
"sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f",
|
||||
"sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c",
|
||||
"sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea",
|
||||
"sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6",
|
||||
"sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05",
|
||||
"sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd",
|
||||
"sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575",
|
||||
"sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a",
|
||||
"sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37",
|
||||
"sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795",
|
||||
"sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f",
|
||||
"sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32",
|
||||
"sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c",
|
||||
"sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01",
|
||||
"sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4",
|
||||
"sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2",
|
||||
"sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921",
|
||||
"sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085",
|
||||
"sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df",
|
||||
"sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102",
|
||||
"sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5",
|
||||
"sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68",
|
||||
"sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==6.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
|
||||
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.4"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
include:
|
||||
- _downloads
|
||||
- _images
|
||||
- _sources
|
||||
- _static
|
169
build-multilang.py
Executable file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
from lxml import html, etree
|
||||
|
||||
base_lang: str = "ru"
|
||||
build_dir: str = "build"
|
||||
per_lang_static: list[str] = [
|
||||
r"documentation_options\.js",
|
||||
r"language_data\.js",
|
||||
r"^(?!basic)\w+-stemmer\.js",
|
||||
r"translations\.js",
|
||||
]
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(build_dir, True)
|
||||
os.mkdir(build_dir)
|
||||
|
||||
# Build languages
|
||||
def sphinx_build(lang: str) -> None:
|
||||
subprocess.run([
|
||||
sys.executable, "-m", "sphinx",
|
||||
"-b", "html",
|
||||
"-D", f"language={lang}",
|
||||
"source",
|
||||
f"{build_dir}/{lang}",
|
||||
])
|
||||
|
||||
languages: list[str] = [base_lang]
|
||||
if os.path.isdir("locale"):
|
||||
languages += os.listdir("locale")
|
||||
|
||||
index_page_lang: str = "en" if "en" in languages else base_lang
|
||||
|
||||
for lang in languages:
|
||||
sphinx_build(lang)
|
||||
|
||||
# Extract common assets
|
||||
for i, lang in enumerate(languages):
|
||||
if i == 0:
|
||||
os.rename(f"{build_dir}/{lang}/_downloads", f"{build_dir}/_downloads")
|
||||
os.rename(f"{build_dir}/{lang}/_images", f"{build_dir}/_images")
|
||||
os.rename(f"{build_dir}/{lang}/CNAME", f"{build_dir}/CNAME")
|
||||
os.rename(f"{build_dir}/{lang}/.nojekyll", f"{build_dir}/.nojekyll")
|
||||
else:
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_downloads")
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_images")
|
||||
os.remove(f"{build_dir}/{lang}/CNAME")
|
||||
os.remove(f"{build_dir}/{lang}/.nojekyll")
|
||||
|
||||
for static_file in glob(f"{build_dir}/{lang}/_static/**/*", recursive=True):
|
||||
if not os.path.isfile(static_file):
|
||||
continue
|
||||
|
||||
relative_path = static_file.removeprefix(f"{build_dir}/{lang}/_static/")
|
||||
matched: bool = False
|
||||
for pattern in per_lang_static:
|
||||
if re.match(pattern, relative_path):
|
||||
matched = True
|
||||
break
|
||||
|
||||
# I have no idea how to make "continue 2" from the loop above so...
|
||||
if matched:
|
||||
continue
|
||||
|
||||
dir = os.path.dirname(relative_path)
|
||||
os.makedirs(f"{build_dir}/_static/{dir}", exist_ok=True)
|
||||
os.rename(static_file, f"{build_dir}/_static/{relative_path}")
|
||||
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_sources")
|
||||
shutil.rmtree(f"{build_dir}/{lang}/.doctrees")
|
||||
os.remove(f"{build_dir}/{lang}/.buildinfo")
|
||||
os.remove(f"{build_dir}/{lang}/objects.inv")
|
||||
|
||||
# Convert all relative routes into absolute
|
||||
def make_links_absolute(file_path: str, link: str) -> str:
|
||||
# Skip local anchor links
|
||||
if link.startswith("#"):
|
||||
return link
|
||||
|
||||
# Skip external links (including links without protocol "//ely.by")
|
||||
if link.startswith("//") or re.match(r"^https?://", link):
|
||||
return link
|
||||
|
||||
if ".html" in link:
|
||||
working_directory = os.getcwd()
|
||||
os.chdir(Path(file_path).parent.absolute())
|
||||
resolved = str(Path(link).resolve())
|
||||
os.chdir(working_directory)
|
||||
|
||||
link = resolved.removeprefix(f"{working_directory}/{build_dir}")
|
||||
link = link.replace("\\", "/") # fix for the Windows
|
||||
|
||||
return link
|
||||
|
||||
# Other links are links to some static assets
|
||||
# There is no need to resolve relative links since _static is placed in the root directory,
|
||||
# so after removing all ../ parts we can safely append / to make the path absolute
|
||||
while link.startswith("../"):
|
||||
link = link.removeprefix("../")
|
||||
|
||||
no_static_link = link.removeprefix("_static/")
|
||||
for pattern in per_lang_static:
|
||||
if re.match(pattern, no_static_link):
|
||||
lang = re.match(fr"^{build_dir}/(\w+)/", file_path).group(1)
|
||||
|
||||
return f"/{lang}/{link}"
|
||||
|
||||
return f"/{link}"
|
||||
|
||||
for file in glob(f"{build_dir}/**/*.html", recursive=True):
|
||||
tree = html.parse(file) # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
root.rewrite_links(lambda link: make_links_absolute(file, link))
|
||||
|
||||
tree.write(file, method="html", encoding="UTF-8")
|
||||
|
||||
# Create index.html for the site root
|
||||
shutil.copyfile(f"{build_dir}/{index_page_lang}/index.html", f"{build_dir}/index.html")
|
||||
index_file_tree = html.parse(f"{build_dir}/index.html") # type: etree._ElementTree
|
||||
index_file_root = index_file_tree.getroot() # type: html.HtmlElement
|
||||
index_file_last_toctree = index_file_root.find_class("toctree-wrapper")[0] # type: html.HtmlElement
|
||||
|
||||
for lang in languages:
|
||||
if lang == index_page_lang:
|
||||
continue
|
||||
|
||||
tree = html.parse(f"{build_dir}/{lang}/index.html") # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
toctree = root.find_class("toctree-wrapper")[0] # type: html.HtmlElement
|
||||
index_file_last_toctree.addnext(toctree)
|
||||
|
||||
index_file_last_toctree = index_file_root.find_class("toctree-wrapper")[-1] # type: html.HtmlElement
|
||||
|
||||
index_file_tree.write(f"{build_dir}/index.html", method="html", encoding="UTF-8")
|
||||
|
||||
# Add cross-lang links to the sidebar
|
||||
sidebar_menus: dict[str, html.HtmlElement] = {}
|
||||
for lang in languages:
|
||||
tree = html.parse(f"{build_dir}/{lang}/index.html") # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
sidebar_menus[lang] = root.find_class("wy-menu")[0]
|
||||
|
||||
for file in glob(f"{build_dir}/**/*.html") + [f"{build_dir}/index.html"]:
|
||||
result = re.match(fr"^{build_dir}/(\w+)/", file)
|
||||
lang: str = result.group(1) if result is not None else index_page_lang
|
||||
|
||||
tree = html.parse(file) # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
sidebar_menu_last = root.find_class("wy-menu")[0] # type: html.HtmlElement
|
||||
for menuLang in sidebar_menus:
|
||||
if menuLang == lang:
|
||||
continue
|
||||
|
||||
sidebar_menu_last.addnext(sidebar_menus[menuLang])
|
||||
sidebar_menu_last = root.find_class("wy-menu")[-1] # type: html.HtmlElement
|
||||
|
||||
tree.write(file, method="html", encoding="UTF-8")
|
8
crowdin.yml
Normal file
@ -0,0 +1,8 @@
|
||||
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||
base_url: https://ely.crowdin.com
|
||||
project_id : 2
|
||||
preserve_hierarchy: true
|
||||
|
||||
files:
|
||||
- source: build/locale/*.pot
|
||||
translation: locale/%two_letters_code%/LC_MESSAGES/%file_name%.po
|
@ -1,3 +0,0 @@
|
||||
Sphinx~=3.0.0
|
||||
sphinx-rtd-theme~=0.4.3
|
||||
sphinx-autobuild~=0.7.1
|
@ -17,4 +17,3 @@
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=/ru/api.html" />
|
||||
<script>
|
||||
window.location.href = '/ru/api.html'
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -1,38 +1,25 @@
|
||||
Ely.by API (симуляция Mojang API)
|
||||
---------------------------------
|
||||
|
||||
Здесь приведена информация об API, совместимом с функционалом `Mojang Api <http://wiki.vg/Mojang_API>`_. Обращаем ваше
|
||||
внимание на то, что это не полноценное API Ely.by, а только набор дополнительных запросов, реализованных на базе нашего
|
||||
`сервера авторизации </minecraft-auth.html>`_.
|
||||
|
||||
Заметки
|
||||
=======
|
||||
|
||||
* API не имеет ограничения на количество запросов. У нас есть просто настроенный fail2ban, который будет банить особо
|
||||
надоедливых клиентов. Такие дела.
|
||||
Здесь приведена информация об API, совместимом с функционалом `Mojang Api <http://wiki.vg/Mojang_API>`_. Обращаем ваше внимание на то, что это не полноценное API Ely.by, а только набор дополнительных запросов, реализованных на базе нашего :doc:`сервера авторизации <minecraft-auth>`.
|
||||
|
||||
Запросы
|
||||
=======
|
||||
|
||||
В этой секции будут описаны запросы и их же варианты для Mojang API. Все запросы выполняются на базовый url
|
||||
``https://authserver.ely.by``.
|
||||
.. note:: API не имеет ограничения на количество запросов. У нас есть просто настроенный fail2ban, который будет банить особо надоедливых клиентов. Такие дела.
|
||||
|
||||
В этой секции будут описаны запросы и их же варианты для Mojang API. Все запросы выполняются на базовый url ``https://authserver.ely.by``.
|
||||
|
||||
UUID по нику на время
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Данный запрос позволяет узнать UUID пользователя по его нику на указанный момент времени. Время задаётся через GET
|
||||
параметр at с unitx timestamp.
|
||||
|
||||
.. note:: На самом деле Ely.by пока не запоминает период смены ника и не обращает внимание на этот запрос. Тем не менее
|
||||
параметр в будущем будет дореализован.
|
||||
Данный запрос позволяет узнать UUID пользователя по его нику на указанный момент времени. Время задаётся через GET параметр at с unix timestamp.
|
||||
|
||||
.. function:: GET /api/users/profiles/minecraft/{username}
|
||||
|
||||
Где username - искомый ник пользователя. Он может быть передан в любом регистре (В Mojang API только строгое
|
||||
совпадение).
|
||||
Где ``{username}`` — искомый ник пользователя. Он может быть передан в любом регистре (В Mojang API только строгое совпадение).
|
||||
|
||||
Обратите так же внимание, что параметры legacy и demo никогда не будут возвращены, т.к. эти параметры не имеют в Ely
|
||||
альтернативы и специфичны только для сервисов Mojang.
|
||||
Обратите так же внимание, что параметры legacy и demo никогда не будут возвращены, т.к. эти параметры не имеют в Ely альтернативы и специфичны только для сервисов Mojang.
|
||||
|
||||
В случае успешного запроса вы получите следующий ответ сервера:
|
||||
|
||||
@ -43,7 +30,7 @@ UUID по нику на время
|
||||
"name": "ErickSkrauch"
|
||||
}
|
||||
|
||||
В случае, если переданный ник не будет найден, вы получите ответ с 204 статусом и пустым телом.
|
||||
В случае, если переданный ник не будет найден, вы получите ответ с ``204`` статусом и пустым телом.
|
||||
|
||||
Никнейм по UUID + история изменений
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -52,8 +39,7 @@ UUID по нику на время
|
||||
|
||||
.. function:: GET /api/user/profiles/{uuid}/names
|
||||
|
||||
Где uuid - валиданый UUID. Валидным будет считаться UUID, написанный через дефисы или без них. В случае передачи
|
||||
невалидной строки, будет возвращён IllegalArgumentException_ с сообщением ``"Invalid uuid format."``.
|
||||
Где ``{uuid}`` — валидный UUID. Валидным будет считаться UUID, написанный через дефисы или без них. В случае передачи невалидной строки, будет возвращён IllegalArgumentException_ с сообщением ``"Invalid uuid format."``.
|
||||
|
||||
В случае успешного запроса вы получите следующий ответ сервера:
|
||||
|
||||
@ -69,10 +55,9 @@ UUID по нику на время
|
||||
}
|
||||
]
|
||||
|
||||
.. note:: Т.к. на Ely.by не реализован алгоритм запоминания момента смены ника, будет возвращаться только 1 элемент.
|
||||
Чуть позже мы добавим полноценную поддержку запоминания момента смены ника.
|
||||
.. note:: Т.к. на Ely.by не реализован алгоритм запоминания момента смены ника, будет возвращаться только 1 элемент. Чуть позже мы добавим полноценную поддержку запоминания момента смены ника.
|
||||
|
||||
В случае, если переданный UUID не будет найден, вы получите ответ с 204 статусом и пустым телом.
|
||||
В случае, если переданный UUID не будет найден, вы получите ответ с ``204`` статусом и пустым телом.
|
||||
|
||||
Список никнеймов в их UUID
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -83,10 +68,7 @@ UUID по нику на время
|
||||
|
||||
В теле запроса или POST параметрах необходимо передать валидный JSON массив искомых ников.
|
||||
|
||||
В массиве должно быть не более 100 ников, в противном случае будет возвращён IllegalArgumentException_ с сообщением
|
||||
``"Not more that 100 profile name per call is allowed."``. В случае, если переданная строка окажется невалидным
|
||||
JSON объектом, будет возвращёно это же исключение, только с текстом ``"Passed array of profile names is an invalid
|
||||
JSON string."``.
|
||||
В массиве должно быть не более 100 ников, в противном случае будет возвращён IllegalArgumentException_ с сообщением ``"Not more that 100 profile name per call is allowed."``. В случае, если переданная строка окажется невалидным JSON объектом, будет возвращено это же исключение, только с текстом ``"Passed array of profile names is an invalid JSON string."``.
|
||||
|
||||
Пример тела запроса:
|
||||
|
||||
@ -115,13 +97,12 @@ UUID по нику на время
|
||||
|
||||
Данные возвращаются в том же порядке, в каком и были запрошены.
|
||||
|
||||
В случае, если один из переданных никнеймов не найден в базе данных, для него не будет возвращено значения (он будет
|
||||
просто пропущен). Учитывайте эту ситуацию при парсинге ответа.
|
||||
В случае, если один из переданных никнеймов не найден в базе данных, для него не будет возвращено значения (он будет просто пропущен). Учитывайте эту ситуацию при парсинге ответа.
|
||||
|
||||
Запрос информации о профиле по UUID
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
См. `запрос профиля для сервера авторизации <minecraft-auth.html#profile-request>`_.
|
||||
См. :ref:`запрос профиля для сервера авторизации <profile-request>`.
|
||||
|
||||
Возможные ошибки
|
||||
================
|
||||
@ -137,11 +118,9 @@ IllegalArgumentException
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
// Пример ошибки при неправильном формате UUID
|
||||
{
|
||||
"error": "IllegalArgumentException",
|
||||
"errorMessage": "Invalid uuid format."
|
||||
}
|
||||
|
||||
``errorMessage`` не всегда совпадает с таковым у Mojang, но в основном это касается только специфичных только для Ely
|
||||
ошибок. Оригинальные же запросы и ожидаемые от них ошибки повторяют тексты Mojang.
|
||||
``errorMessage`` не всегда совпадает с таковым у Mojang, но в основном это касается только специфичных только для Ely ошибок. Оригинальные же запросы и ожидаемые от них ошибки повторяют тексты Mojang.
|
@ -24,7 +24,7 @@ Authlib-injector
|
||||
|
||||
Если вы запускаете игру через лаунчер, то в его настройках необходимо найти поле для указания дополнительных аргументов JVM, куда необходимо в самое начало вставить строку, приведённую выше.
|
||||
|
||||
.. figure:: ../_static/authlib-injector/launcher-jvm-options.png
|
||||
.. figure:: images/authlib-injector/launcher-jvm-options.png
|
||||
:align: center
|
||||
:alt: Редактирование аргументов JVM
|
||||
|
||||
@ -40,7 +40,7 @@ Authlib-injector
|
||||
|
||||
При запуске сервера вы должны увидеть сообщение об активации authlib-injector:
|
||||
|
||||
.. figure:: ../_static/authlib-injector/server-startup-messages.png
|
||||
.. figure:: images/authlib-injector/server-startup-messages.png
|
||||
:align: center
|
||||
:alt: Сообщение при запуске сервера
|
||||
|
@ -29,7 +29,7 @@ import datetime
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = ['sphinx.ext.ifconfig']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@ -45,7 +45,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Ely.by Documentation'
|
||||
copyright = str(datetime.datetime.now().year) + ', ErickSkrauch'
|
||||
copyright = str(datetime.datetime.now().year) + ', Ely.by'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@ -58,7 +58,7 @@ release = ''
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
||||
language = 'ru'
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
@ -258,22 +258,24 @@ texinfo_documents = [
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
# -- Options for sphinx-intl ----------------------------------------------
|
||||
|
||||
locale_dirs = ['../locale/']
|
||||
gettext_compact = False
|
||||
|
||||
# -- Static files generation rules ----------------------------------------
|
||||
|
||||
static_files = [
|
||||
'../CNAME',
|
||||
'../_config.yml',
|
||||
'api.html',
|
||||
'minecraft-auth.html',
|
||||
'oauth.html',
|
||||
'skin-system.html',
|
||||
'../.nojekyll',
|
||||
]
|
||||
|
||||
from shutil import copyfile
|
||||
from os import path
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
def copy_static_files(app, _):
|
||||
# type: (Sphinx, None) -> None
|
||||
if app.builder.name != 'html':
|
||||
def copy_static_files(app: Sphinx, _) -> None:
|
||||
if app.builder.name != "html":
|
||||
return
|
||||
|
||||
for src_name in static_files:
|
||||
@ -286,4 +288,4 @@ def copy_static_files(app, _):
|
||||
copyfile(src_path, target_path)
|
||||
|
||||
def setup(app):
|
||||
app.connect('build-finished', copy_static_files)
|
||||
app.connect("build-finished", copy_static_files)
|
||||
|
@ -1,83 +0,0 @@
|
||||
Authlib-injector
|
||||
----------------
|
||||
|
||||
**authlib-injector** is a library that allows you to spoof authorization and session server addresses in the Authlib, without modifying the library itself. It's designed as an javaagent.
|
||||
|
||||
This library significantly simplifies the installation of an alternative authorization service in the game client and server, since transformation occurs during application bootstrap process.
|
||||
|
||||
You can download the latest version from the `releases page on GitHub <https://github.com/yushijinhun/authlib-injector/releases/latest>`_.
|
||||
|
||||
Here is the documentation of the key aspects of installing and using the library. For more information, see the `original documentation in Chinese <https://github.com/yushijinhun/authlib-injector/wiki>`_.
|
||||
|
||||
.. _client:
|
||||
|
||||
Installing in a game client
|
||||
===========================
|
||||
|
||||
.. attention:: This section describes how to install the authlib-injector into the game. The game launcher still needs to implement the authorization flow itself in order to pass the ``accessToken`` to the game.
|
||||
|
||||
To install the library, you need to specify it as a javaagent for the game. You can do this by prepending the line ``-javaagent:/path/to/file/authlib-injector.jar=ely.by`` as a game launching param. As the result, the launch command should look like this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
java -javaagent:/path/to/file/authlib-injector.jar=ely.by -jar minecraft.jar
|
||||
|
||||
If you run the game through a launcher, then in its settings you need to find a field for specifying additional JVM arguments, in which you need to insert the line above at the beginning.
|
||||
|
||||
.. figure:: ../_static/authlib-injector/launcher-jvm-options.png
|
||||
:align: center
|
||||
:alt: Editing JVM arguments
|
||||
|
||||
.. _server:
|
||||
|
||||
Installing on a server
|
||||
======================
|
||||
|
||||
Just as in the case with the game client, the library must be specified as javaagent. `Download the library <https://github.com/yushijinhun/authlib-injector/releases/latest>`_ and put in the server's directory. Then add the javaagent call to the server launch command:
|
||||
|
||||
| Before: ``java -jar minecraft_server.jar``
|
||||
| After: ``java -javaagent:authlib-injector.jar=ely.by -jar minecraft_server.jar``
|
||||
|
||||
During server startup you should see a message about the activation of the authlib-injector:
|
||||
|
||||
.. figure:: ../_static/authlib-injector/server-startup-messages.png
|
||||
:align: center
|
||||
:alt: Message at server startup
|
||||
|
||||
BungeeCord
|
||||
~~~~~~~~~~
|
||||
|
||||
The authlib-injector must be installed directly on the BungeeCord itself, as well as **on all backends** behind it. Note the configuration of the online-mode parameter:
|
||||
|
||||
* The BungeeCord's configuration (``config.yml``) should contain ``online_mode=true``;
|
||||
* The servers behind the proxy must contain in their configuration (``server.properties``) the value ``online-mode=false``.
|
||||
|
||||
Using such configuration authorization will work for all logging in players and the internal servers will correctly display player skins.
|
||||
|
||||
LaunchHelper
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Not all game hostings allow direct modifications of launch arguments. To get around this limitation, you can use a special server that runs the game server by mixing authlib-injector into it. To install, follow these instructions:
|
||||
|
||||
#. Download the corresponding LaunchHelper for your operating system from the `releases page <https://github.com/Codex-in-somnio/LaunchHelper/releases/latest>`_.
|
||||
|
||||
#. Upload this file and the ``authlib-injector.jar`` file to the server folder on your hosting site.
|
||||
|
||||
#. Also create a ``launchhelper.properties`` file and put the following contents into it:
|
||||
|
||||
.. code-block::
|
||||
|
||||
javaAgentJarPath=authlib-injector.jar
|
||||
javaAgentOptions=ely.by
|
||||
execJarPath=minecraft_server.jar
|
||||
|
||||
Where ``javaAgentJarPath`` contains the path to the authlib-injector.jar file and ``execJarPath`` contains the name of the server file.
|
||||
|
||||
#. In the hosting control panel, specify the ``LaunchHelper.jar`` as the server file.
|
||||
|
||||
If you can't change the executable file, you should rename the ``LaunchHelper.jar`` file to match your hosting requirements (usually, ``server.jar``). In this case, you should have the following file structure:
|
||||
|
||||
* ``server.jar`` - the LaunchHelper file.
|
||||
* ``minecraft_server.jar`` - your server core.
|
||||
* ``authlib-injector.jar`` - the authlib-injector file.
|
||||
* ``launchhelper.properties`` - the configuration file for the LaunchHelper.
|
@ -1,424 +0,0 @@
|
||||
Authorization via OAuth2 protocol
|
||||
---------------------------------
|
||||
|
||||
On this page you'll find how to implement OAuth2 authorization on your project through the Ely.by Accounts service.
|
||||
The implementation of this protocol will allow your users to authorize using their Ely.by account.
|
||||
|
||||
Application registration
|
||||
========================
|
||||
|
||||
First you need to `create a new application <https://account.ely.by/dev/applications/new>`_. Select **Website** as the
|
||||
application type. For the *Redirect URI* you can get away with just specifying the domain, but to increase security
|
||||
it's advised to use the full redirect path. Here are examples of valid addresses:
|
||||
|
||||
* :samp:`http://site.com`
|
||||
* :samp:`http://site.com/oauth/ely`
|
||||
* :samp:`http://site.com/oauth.php?provider=ely`
|
||||
|
||||
After a successful creation of an application, you'll be taken to the page containing a list of all your applications.
|
||||
If you click on the name of an application you'll see its ``clientId`` identifier and its ``clientSecret`` secret.
|
||||
They'll become important in later steps.
|
||||
|
||||
Authorization initiation
|
||||
========================
|
||||
|
||||
To initiate the authorization flow, you'll have to redirect the user to the following URL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
https://account.ely.by/oauth2/v1?client_id=<clientId>&redirect_uri=<redirectUri>&response_type=code&scope=<scopesList>
|
||||
|
||||
.. list-table:: Valid query parameters
|
||||
:widths: 1 1 98
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Value example
|
||||
- Description
|
||||
* - *clientId*
|
||||
- :samp:`ely`
|
||||
- **Required**. ClientId that was received during registration.
|
||||
* - *redirect_uri*
|
||||
- :samp:`http://site.com/oauth.php`
|
||||
- **Required**. Return-forwarding address, which is matches the address specified during the application
|
||||
registration.
|
||||
* - *response_type*
|
||||
- :samp:`code`
|
||||
- **Required**. Response type. At the moment, only ``code`` is supported.
|
||||
* - *scope*
|
||||
- :samp:`account_info account_email`
|
||||
- **Required**. The list of permissions that you want to access, separated by spaces. See all available permissions
|
||||
in the `section below <#available-scopes>`_.
|
||||
* - *state*
|
||||
- :samp:`isfvubuysdboinsbdfvit`
|
||||
- Randomly generated string. Used as a session identifier to increase security. Will be returned unchanged after
|
||||
authorization is completed.
|
||||
* - *description*
|
||||
- :samp:`यो अनुप्रयोग विवरण`
|
||||
- If your application is available in several languages, you can use this field to override the default description
|
||||
in accordance with user's preferred language.
|
||||
* - *prompt*
|
||||
- :samp:`consent` or :samp:`select_account`
|
||||
- Forcibly display the request for permissions (``consent``) or forcibly request an account selection
|
||||
(``select_account``).
|
||||
* - *login_hint*
|
||||
- :samp:`erickskrauch` or :samp:`erickskrauch@ely.by`
|
||||
- If a user has several accounts, then specifying username or user email in this parameter will automatically
|
||||
select corresponding account. This is useful in a case of re-login after the token has expired.
|
||||
|
||||
.. _available_scopes:
|
||||
.. list-table:: List of available scopes
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - **account_info**
|
||||
- Get user information.
|
||||
* - **account_email**
|
||||
- Response to a request for user information will also contain user's email address.
|
||||
* - **offline_access**
|
||||
- With an ``access_token`` you will also recieve a ``refresh_token``. See more at
|
||||
`the corresponding section <#refresh-token-grant>`_.
|
||||
* - **minecraft_server_session**
|
||||
- It will be possible to use ``access_token`` as a session identifier for the Minecraft.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
After creating the link, place it in your template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<a href="<your_link>">Login via Ely.by</a>
|
||||
|
||||
After clicking on the URL a user will be redirected to our login page after which they'll be redirected back to the
|
||||
address specified in the ``redirect_uri`` parameter.
|
||||
|
||||
Reverse redirection returns as ``<redirect_uri>?code=<auth_code>&state=<state>`` for a successful authorization and
|
||||
``<redirect_uri?error=<error_identifier>&error_message=<error_description>`` for a failed one.
|
||||
|
||||
Examples of successful and unsuccessful redirects:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
http://site.com/oauth/ely.php?code=dkpEEVtXBdIcgdQWak4SOPEpTJIvYa8KIq5cW9GJ&state=ajckasdcjasndckbsadc
|
||||
http://site.com/oauth/ely.php?error=access_denied&error_message=The+resource+owner+or+authorization+server+denied+the+request.
|
||||
|
||||
.. _authorization-code-grant:
|
||||
|
||||
Exchange auth code for a access key
|
||||
===================================
|
||||
|
||||
After receiving an authorization code (``auth_code``), you'll need to exchange it for an authorization key
|
||||
(``access_key``). To do this, you must perform a POST request to the URL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
https://account.ely.by/api/oauth2/v1/token
|
||||
|
||||
And pass in following parameters:
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - ``client_id``
|
||||
- ClientID that was received during registration.
|
||||
* - ``client_secret``
|
||||
- ClientSecret that was received during application registration.
|
||||
* - ``redirect_uri``
|
||||
- The exact URI that was used for user redirection.
|
||||
* - ``grant_type``
|
||||
- In this case, ``authorization_code`` should be used.
|
||||
|
||||
**An example of the exchange in PHP:**
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// This variable will store your OAuth2 settings
|
||||
$oauthParams = [
|
||||
'client_id' => 'ely', // Your ClientId that was received during registration
|
||||
'client_secret' => 'Pk4uCtZw5WVlSUpvteJuTZkVqHXZ6aNtTaLPXa7X', // Your ClientSecret that was received during registration
|
||||
'redirect_uri' => 'http://someresource.by/oauth/some.php', // Address where you expect to get a user back (current url)
|
||||
'grant_type' => 'authorization_code',
|
||||
];
|
||||
|
||||
// If an error occurs, then the script will stop its execution
|
||||
if (isset($_GET['error'])) {
|
||||
echo $_GET['error_message'];
|
||||
return;
|
||||
}
|
||||
|
||||
// We execute the code below only if the authorization code have arrived
|
||||
if (!is_null($_GET['code'])) {
|
||||
$oauthParams['code'] = $_GET['code'];
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://account.ely.by/api/oauth2/v1/token');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($oauthParams));
|
||||
$out = json_decode(curl_exec($curl), true);
|
||||
curl_close($curl);
|
||||
}
|
||||
|
||||
Notes to the code:
|
||||
|
||||
* First, we declare the ``$oauthParams`` variable which will store the values that we got after registering the
|
||||
application.
|
||||
|
||||
* Then we check if there was an error. In which case, we immediately stop the execution.
|
||||
|
||||
* Then we create a POST request to exchange the ``code`` for an ``access_token``, passing all required fields in the
|
||||
process.
|
||||
|
||||
* Then we execute the request, get the answer and parse it from JSON into the associative array.
|
||||
|
||||
.. _authorization-code-grant-response:
|
||||
|
||||
Server response
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In case of a successful request, the response body will contain the result of exchanging the authorization code for an
|
||||
``access_token``. Data is a JSON document and can be easily interpreted by tools of a used programming language.
|
||||
|
||||
The JSON document body will contain the following fields:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"access_token": "4qlktsEiwgspKEAotazem0APA99Ee7E6jNryVBrZ",
|
||||
"refresh_token": "m0APA99Ee7E6jNryVBrZ4qlktsEiwgspKEAotaze", // Presented only if the request had offline_access scope
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 86400 // Number of seconds that token is active for
|
||||
}
|
||||
|
||||
At this process authorization procedure is over. The resulting ``access_token`` can be used to obtain user information
|
||||
and to interact with our API.
|
||||
|
||||
Getting user information
|
||||
========================
|
||||
|
||||
If the received token has the ``account_info`` scope, then you can request information about the user's account.
|
||||
To do it, you have to send a request to the URL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
https://account.ely.by/api/account/v1/info
|
||||
|
||||
To send ``access_token``, the ``Authorization`` header is used with the value of ``Bearer {access_token}``.
|
||||
|
||||
**An example of getting user information in PHP:**
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$accessToken = 'some_access_token_value';
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://account.ely.by/api/account/v1/info');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
'Authorization: Bearer ' . $accessToken,
|
||||
]);
|
||||
$result = json_decode(curl_exec($curl), true);
|
||||
curl_close($curl);
|
||||
|
||||
In response, you will receive a JSON document with the following contents:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "ffc8fdc9-5824-509e-8a57-c99b940fb996",
|
||||
"username": "ErickSkrauch",
|
||||
"registeredAt": 1470566470,
|
||||
"profileLink": "http:\/\/ely.by\/u1",
|
||||
"preferredLanguage": "be",
|
||||
"email": "erickskrauch@ely.by"
|
||||
}
|
||||
|
||||
Note that the ``email`` field will only be present when the ``account_email`` scope has been requested.
|
||||
|
||||
.. note:: In the future, the number of returned fields may increase, but existing ones will remain the same.
|
||||
|
||||
.. _refresh-token-grant:
|
||||
|
||||
Refreshing access token
|
||||
=======================
|
||||
|
||||
If you have requested the scope ``offline_access`` during authorization, then along with your ``access_token`` you'll
|
||||
also get ``refresh_token``. This token doesn't expire and can be used to obtain a new access token when that one
|
||||
expires.
|
||||
|
||||
To perform a token update, you have to send a POST request to the same URL that was used for
|
||||
`exchanging the auth code for an access token <#authorization-code-grant>`_, but with the next parameters:
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - ``client_id``
|
||||
- ClientClientID that was received during registration.
|
||||
* - ``client_secret``
|
||||
- ClientSecret that was received during application registration.
|
||||
* - ``scope``
|
||||
- The same scopes that were obtained for the initial access token. An attempt to extend this list will cause an
|
||||
error.
|
||||
* - ``refresh_token``
|
||||
- The token itself that was obtained along with the access token.
|
||||
|
||||
**Example of a token refreshing in PHP:**
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// refresh_token that was receive after an authorization
|
||||
$refreshToken = 'm0APA99Ee7E6jNryVBrZ4qlktsEiwgspKEAotaze';
|
||||
|
||||
$requestParams = [
|
||||
'client_id' => 'ely', // Your ClientId, that was received during registration
|
||||
'client_secret' => 'Pk4uCtZw5WVlSUpvteJuTZkVqHXZ6aNtTaLPXa7X', // Your ClientSecret, that was received during registration
|
||||
'scope' => 'account_info account_email',
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
];
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://account.ely.by/api/oauth2/v1/token');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($requestParams));
|
||||
$result = json_decode(curl_exec($curl), true);
|
||||
curl_close($curl);
|
||||
|
||||
The answer will have exactly the same body as the result of
|
||||
`exchanging auto code for an access token <#authorization-code-grant-response>`_. The ``refresh_token`` field will be
|
||||
absent.
|
||||
|
||||
Available libraries
|
||||
===================
|
||||
|
||||
A simpler way is to use a ready-made library, to which you'll only have to provide registration parameters.
|
||||
Listed below are libraries for various programming languages. You can extend this list by providing your own library.
|
||||
|
||||
* **PHP**:
|
||||
|
||||
- [Official] https://github.com/elyby/league-oauth2-provider
|
||||
|
||||
* **Ruby**:
|
||||
|
||||
- [Official] https://github.com/elyby/omniauth-ely
|
||||
|
||||
Possible errors
|
||||
================
|
||||
|
||||
Below are the typical errors that you may receive after transmitting incorrect data to the authorization server.
|
||||
If you encounter an error that is not described in this documentation, please report it via
|
||||
`feedback form <http://ely.by/site/contact>`_.
|
||||
|
||||
.. _auth-start-errors:
|
||||
|
||||
Errors during authorization initiation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This section describes the errors displayed when a user is redirected from your site to our authorization initiation
|
||||
page.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid request ({parameter} required).
|
||||
|
||||
This error means that you did not pass all the required parameters. To solve this error just add the missing parameter.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid response type '{invalid_response_type_value}'.
|
||||
|
||||
This error indicates that you passed an unsupported type of ``response_type``. Currently, the only supported value is
|
||||
``code``.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid scope '{invalid_scope}'.
|
||||
|
||||
The error indicates that an unknown scope was requested. Make sure you request `supported scopes <#available-scopes>`_.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Can not find application you are trying to authorize.
|
||||
|
||||
This error indicates that the passed parameters do not correspond to any of the registered applications. To solve the
|
||||
problem, fix your ``client_id`` and ``redirect_uri`` values.
|
||||
|
||||
.. _issue-token-errors:
|
||||
|
||||
Errors when exchanging code for a key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If an error occurs, instead of the expected response with the ``200`` status, you will receive a ``40x`` code and the
|
||||
following 2 fields:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"error": "invalid_request",
|
||||
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"code\" parameter."
|
||||
}
|
||||
|
||||
The ``error`` field contains the system error identifier, and ``error_description`` describes the error in English
|
||||
language.
|
||||
|
||||
**Possible error values:**
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - ``invalid_request``
|
||||
- Not all the required request parameters were passed or the ``code`` value was not found in the issued codes
|
||||
database.
|
||||
* - ``unsupported_grant_type``
|
||||
- This error indicates that you tried to authorize using an unknown for our OAuth2 server Grant-type.
|
||||
* - ``invalid_client``
|
||||
- This error occurs when the trio of values ``client_id``, ``client_secret`` and ``redirect_uri`` didn't match
|
||||
with any of the registered applications.
|
||||
|
||||
Errors when requesting user information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Response status ``401`` indicates that the ``Authorization`` header is not present in the request or its value formed
|
||||
incorrectly. The response body will be as follows:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name": "Unauthorized",
|
||||
"status": 401,
|
||||
"message": "Your request was made with invalid credentials."
|
||||
}
|
||||
|
||||
A response with the ``403`` status indicates that the token transferred in the ``Authorization`` header does not contain
|
||||
the ``account_info`` scope or it has expired. The response will be in the following format:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name": "Forbidden",
|
||||
"status": 403,
|
||||
"message": "You are not allowed to perform this action."
|
||||
}
|
||||
|
||||
Errors while updating access token
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When updating the access token you may encounter the same errors from
|
||||
`exchanging auth code for an access token <#issue-token-errors>`_, as well as several new ones:
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - ``invalid_request``
|
||||
- Not all the required request parameters were passed or the ``refresh_token`` value wasn't found in the issued tokens database.
|
||||
* - ``invalid_scope``
|
||||
- The unsupported scope was listed or requested more scopes than the original token had.
|
@ -1,201 +0,0 @@
|
||||
Skins system
|
||||
------------
|
||||
|
||||
On this page you'll find information about available endpoints of Ely.by's skins system service. You can use any of
|
||||
them as an secondary or primary source of skins for your project.
|
||||
|
||||
Ely.by's skins system service provides `proxying of textures from Minecraft premium users <#textures-proxy>`_,
|
||||
which means that using this service, your players will see both premium Minecraft users' skins and Ely.by users' skins.
|
||||
|
||||
We strive to comply with the official skins system and do not support ears and HD-skins. The system supports capes,
|
||||
but doesn't allow players to wear them on their own.
|
||||
|
||||
If you have suggestions for improving the existing functionality, please
|
||||
`create a new Issue <https://github.com/elyby/chrly/issues/new>`_ at the
|
||||
`Chrly project repository <https://github.com/elyby/chrly>`_.
|
||||
|
||||
.. note:: You can find more detailed information about the implementation of the skins system server in the
|
||||
`Chrly project repository <https://github.com/elyby/chrly>`_.
|
||||
|
||||
Requests URLs
|
||||
=============
|
||||
|
||||
The skins system is located at the :samp:`http://skinsystem.ely.by` domain.
|
||||
|
||||
In all queries, the :samp:`nickname` param must be replaced by the player's name. The value is case-insensitive.
|
||||
|
||||
.. _skin-request:
|
||||
.. function:: /skins/{nickname}.png
|
||||
|
||||
URL for downloading a skin texture. The :samp:`.png` extension can be omitted. If textures aren't found,
|
||||
the server will return a :samp:`404` status response.
|
||||
|
||||
.. _cape-request:
|
||||
.. function:: /cloaks/{nickname}.png
|
||||
|
||||
URL for downloading a cape texture. The :samp:`.png` extension can be omitted. If textures aren't found,
|
||||
the server will return a :samp:`404` status response.
|
||||
|
||||
.. function:: /textures/{nickname}
|
||||
|
||||
Via this URL you can get textures in the format specified in the :samp:`textures` field of JSON property with the
|
||||
same name in response to a
|
||||
`request for signed textures <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"SKIN": {
|
||||
"url": "http://example.com/skin.png",
|
||||
"metadata": {
|
||||
"model": "slim"
|
||||
}
|
||||
},
|
||||
"CAPE": {
|
||||
"url": "http://example.com/cape.png"
|
||||
}
|
||||
}
|
||||
|
||||
Depending on the availability of textures for the player, fields :samp:`SKIN` or :samp:`CAPE` may be absent.
|
||||
Unless the skin model is :samp:`slim`, the :samp:`metadata` field will be omitted.
|
||||
|
||||
The server will return an empty response with :samp:`204` status, if textures aren't found.
|
||||
|
||||
.. function:: /profile/{nickname}
|
||||
|
||||
This endpoint is an analog of the
|
||||
`player profile query in the Mojang's API <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_, but
|
||||
instead of UUID user is queried by his nickname. Just like in the Mojang's API, you can append ``?unsigned=false``
|
||||
to the URL to get textures with a signature. The response will also include an additional property with ``name``
|
||||
**ely**.
|
||||
|
||||
If the user has no textures, they'll be requested through the Mojang's API, but the Mojang's signature will be
|
||||
discarded and textures will be re-signed using `our signature key <#signature-verification-key-request>`_.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"id": "ffc8fdc95824509e8a57c99b940fb996",
|
||||
"name": "ErickSkrauch",
|
||||
"properties": [
|
||||
{
|
||||
"name": "textures",
|
||||
"signature": "eks3dLJWzod92dLfWH6Z8uc6l3+IvrZtTj3zjwnj0AdVt44ODKoL50N+RabYxf7zF3C7tlJwT1oAtydONrxXUarqUlpVeQzLlfsuqUKBLi0L+/Y9yQLG3AciNqzEWq3hYaOsJrsaJday/hQmKFnpXEFCThTMpSuZhoAZIiH4VG48NhP70U93ejyXF9b1nPYnXP6k7BVB8LYSzcjZfdqY88jQJbbvRzOyX14ZSD0Ma92jceLNKmkTVc2UfRLUNXtQKtVSFUzlAjCXPJW89IIOZTRqLg65qstWwBvn6VuikyUB5EIxM8vuCh7zTkrMOx1v2Q0xIj8YSFcbnBH2bo87SYOIe1bOK57ZEeUJqY6uSgMlWs7dI5D3nmhFptErm72hg55Axdo1xbG4mvnmLYF7SA4yMDSytPPL+kA+sw3pafnvU2IZo38gqJSDOOpkOpdhUoHx85fzRJL8AcLSJiFlCZDl4pSi3cVuKy/xY5ohT/fJ6GEqpbZp3gACymn47zzI42VSh6j1DQnx2wnhqalTv0kE3qpAFpK/htSboQkFCW/bULO3b+vgU87XPlReT7UtH4yGLtixgs5GC8AzBraN8vOMv8TZCX9ab6mBBjOoDJjXa8Tq637TC75GxRHlpAN2jRHYvyp2zJwjUrML3u4eD4osHW+VBfl8D2l3nLJuemQ=",
|
||||
"value": "eyJ0aW1lc3RhbXAiOjE2MTQ5MzczMjc0MzcsInByb2ZpbGVJZCI6ImZmYzhmZGM5NTgyNDUwOWU4YTU3Yzk5Yjk0MGZiOTk2IiwicHJvZmlsZU5hbWUiOiJFcmlja1NrcmF1Y2giLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly9lbHkuYnkvc3RvcmFnZS9za2lucy82OWM2NzQwZDI5OTNlNWQ2ZjZhN2ZjOTI0MjBlZmMyOS5wbmcifX19"
|
||||
},
|
||||
{
|
||||
"name": "ely",
|
||||
"value": "but why are you asking?"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The server will return an empty response with ``204`` status if the nickname wasn't found locally nor via the
|
||||
Mojang's API.
|
||||
|
||||
.. _signature-verification-key-request:
|
||||
.. function:: /signature-verification-key.der
|
||||
|
||||
This endpoint returns a public key that can be used to verify a texture's signature. The key is provided in ``DER``
|
||||
format, so it can be used directly in the Authlib, without modifying the signature checking algorithm.
|
||||
|
||||
.. function:: /signature-verification-key.pem
|
||||
|
||||
The same endpoint as the previous one, except that it returns the key in ``PEM`` format.
|
||||
|
||||
.. function:: /textures/signed/{nickname}
|
||||
|
||||
This request is used in our `server skins system plugin <http://ely.by/server-skins-system>`_ to load textures with
|
||||
the original Mojang's signature. The textures received this way can be transferred to an unmodified game client
|
||||
without any changes. The answer will also include additional property with :samp:`name` equal to **ely**.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"id": "ffc8fdc95824509e8a57c99b940fb996",
|
||||
"name": "ErickSkrauch",
|
||||
"properties": [
|
||||
{
|
||||
"name": "textures",
|
||||
"signature": "QH+1rlQJYk8tW+8WlSJnzxZZUL5RIkeOO33dq84cgNoxwCkzL95Zy5pbPMFhoiMXXablqXeqyNRZDQa+OewgDBSZxm0BmkNmwdTLzCPHgnlNYhwbO4sirg3hKjCZ82ORZ2q7VP2NQIwNvc3befiCakhDlMWUuhjxe7p/HKNtmKA7a/JjzmzwW7BWMv8b88ZaQaMaAc7puFQcu2E54G2Zk2kyv3T1Bm7bV4m7ymbL8McOmQc6Ph7C95/EyqIK1a5gRBUHPEFIEj0I06YKTHsCRFU1U/hJpk98xXHzHuULJobpajqYXuVJ8QEVgF8k8dn9VkS8BMbXcjzfbb6JJ36v7YIV6Rlt75wwTk2wr3C3P0ij55y0iXth1HjwcEKsg54n83d9w8yQbkUCiTpMbOqxTEOOS7G2O0ZDBJDXAKQ4n5qCiCXKZ4febv4+dWVQtgfZHnpGJUD3KdduDKslMePnECOXMjGSAOQou//yze2EkL2rBpJtAAiOtvBlm/aWnDZpij5cQk+pWmeHWZIf0LSSlsYRUWRDk/VKBvUTEAO9fqOxWqmSgQRUY2Ea56u0ZsBb4vEa1UY6mlJj3+PNZaWu5aP2E9Unh0DIawV96eW8eFQgenlNXHMmXd4aOra4sz2eeOnY53JnJP+eVE4cB1hlq8RA2mnwTtcy3lahzZonOWc=",
|
||||
"value": "eyJ0aW1lc3RhbXAiOjE0ODYzMzcyNTQ4NzIsInByb2ZpbGVJZCI6ImM0ZjFlNTZmNjFkMTQwYTc4YzMyOGQ5MTY2ZWVmOWU3IiwicHJvZmlsZU5hbWUiOiJXaHlZb3VSZWFkVGhpcyIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS83Mzk1NmE4ZTY0ZWU2ZDhlYzY1NmFkYmI0NDA0ZjhlYmZmMzQxMWIwY2I5MGIzMWNiNDc2ZWNiOTk2ZDNiOCJ9fX0="
|
||||
},
|
||||
{
|
||||
"name": "ely",
|
||||
"value": "but why are you asking?"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
By default textures proxying isn't used for this query. To enable it, add an additional GET parameter
|
||||
:samp:`?proxy=true`.
|
||||
|
||||
The server will return an empty response with :samp:`204` status, if textures aren't found.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
You can also pass a range of additional GET parameters while making any of the above requests. They will be used
|
||||
to analyze the usage of the service by different versions of the game.
|
||||
|
||||
:version: The version of the protocol by which skins will be requested. The current version is :samp:`2`,
|
||||
i.e. you need to specify :samp:`version=2`.
|
||||
|
||||
:minecraft_version: The version of Minecraft that the request is made from.
|
||||
|
||||
:authlib_version: The version of the Authlib used. This option is relevant for Minecraft versions 1.7.6+,
|
||||
where a separate library is used to load skins instead of in-game code.
|
||||
|
||||
Here is an example of a textures request with parameters described above:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
http://skinsystem.ely.by/textures/erickskrauch?version=2&minecraft_version=1.14.0&authlib_version=1.5.25
|
||||
|
||||
Additional URLs
|
||||
+++++++++++++++
|
||||
|
||||
You can also perform a skin and cape request by passing the nickname through the GET parameter. This feature is used
|
||||
to pass analytical parameters of game versions up to 1.5.2, where the nickname is simply appended to the end of the
|
||||
line. To do this, the entire string is arranged in such a way that the last parameter is :samp:`name`, after appending
|
||||
a nickname to which you get a full request string for textures.
|
||||
|
||||
.. function:: /skins?name={nickname}.png
|
||||
|
||||
See the `skin request <#skin-request>`_.
|
||||
|
||||
.. function:: /cloaks?name={nickname}.png
|
||||
|
||||
See the `cape request <#cape-request>`_.
|
||||
|
||||
Examples of requests for textures with parameters from above:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
http://skinsystem.ely.by/skins?version=2&minecraft_version=1.5.2&name=erickskrauch.png
|
||||
http://skinsystem.ely.by/cloaks?version=2&minecraft_version=1.4.7&name=notch
|
||||
|
||||
.. _textures-proxy:
|
||||
|
||||
Textures proxying
|
||||
=================
|
||||
|
||||
Ely.by's skins system service obtains textures from the official skin system in a case where no information about
|
||||
textures for the requested username was found in the database. The request will also be proxied if a skin entry is
|
||||
found, but it's default.
|
||||
|
||||
To improve the throughput of the proxying algorithm, information about textures is cached in 2 stages:
|
||||
|
||||
* Player's names and UUIDs matches are stored
|
||||
`for 30 days <https://help.minecraft.net/hc/en-us/articles/360034636712-Minecraft-Usernames#article-container:~:text=How%20often%20can%20I%20change%20my%20username%3F>`_.
|
||||
|
||||
* Information about textures isn't updated more often than
|
||||
`once a minute <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape:~:text=You%20can%20request%20the%20same%20profile%20once%20per%20minute>`_.
|
||||
|
||||
If you own a Minecraft premium account, but your nickname is busy, please contact our
|
||||
`support team <http://ely.by/site/contact>`_ and after a short check we'll pass the nickname on to you.
|
||||
|
||||
Ready-made implementations
|
||||
==========================
|
||||
|
||||
Ready-made patch implementations and installation instructions can be found at the
|
||||
`download section of the main Ely.by website <http://ely.by/load>`_.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -1,21 +1,13 @@
|
||||
Welcome to the Ely.by documentation!
|
||||
====================================
|
||||
Добро пожаловать в документацию Ely.by!
|
||||
=======================================
|
||||
|
||||
In this documentation you will find information about the public services of the Ely.by project, using which you'll be
|
||||
able to integrate your projects with the Ely.by services.
|
||||
В этой документации вы найдёте информацию о публичных сервисах проекта Ely.by, используя которые вы сможете самостоятельно реализовать свои программные продукты для совместной работы с сервисом Ely.by.
|
||||
|
||||
You are free to improve this documentation in the `documentation's repository <https://github.com/elyby/docs>`_.
|
||||
Вы можете свободно улучшать и вносить предложения по изменениям в документацию в `репозитории проекта <https://github.com/elyby/docs>`_.
|
||||
|
||||
.. toctree::
|
||||
:caption: English articles:
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
en/*
|
||||
|
||||
.. toctree::
|
||||
:caption: Статьи на русском:
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
ru/*
|
||||
*
|
||||
|
@ -1,8 +0,0 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=/ru/minecraft-auth.html" />
|
||||
<script>
|
||||
window.location.href = '/ru/minecraft-auth.html'
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -3,8 +3,7 @@
|
||||
|
||||
Здесь приведена информация по авторизации для лаунчеров и серверов Minecraft через сервис авторизации Ely.by.
|
||||
|
||||
Протокол авторизации реализован максимально похожим на `оригинальный протокол авторизации Mojang <http://wiki.vg/Authentication>`_,
|
||||
но тем не менее эта документация описывает все доступные функции конкретно сервиса авторизации Ely.by.
|
||||
Протокол авторизации реализован максимально похожим на `оригинальный протокол авторизации Mojang <http://wiki.vg/Authentication>`_, но тем не менее эта документация описывает все доступные функции конкретно сервиса авторизации Ely.by.
|
||||
|
||||
Общие положения
|
||||
===============
|
||||
@ -13,8 +12,7 @@
|
||||
|
||||
* При успешном запросе, сервер вернёт ответ со статусом 200. Любой другой код свидетельствует об ошибке.
|
||||
|
||||
* Сервер всегда отвечает JSON данными, кроме случаев системных ошибок и ответов на legacy запросы. Учитывайте это для
|
||||
отображения пользователю правильного сообщения об ошибке.
|
||||
* Сервер всегда отвечает JSON данными, кроме случаев системных ошибок и ответов на legacy запросы. Учитывайте это для отображения пользователю правильного сообщения об ошибке.
|
||||
|
||||
* В случае стандартной ошибки, вы получите следующие данные:
|
||||
|
||||
@ -122,8 +120,7 @@
|
||||
|
||||
.. note:: В оригинальном протоколе так же передаётся значение ``selectedProfile``, но в реализации Mojang он не влияет ни на что. Наша реализация сервера авторизации игнорирует этот параметр и опирается на значения ``accessToken`` и ``clientToken``.
|
||||
|
||||
В случае получения какой-либо предусмотренной ошибки, следует заново запросить пароль пользователя и произвести
|
||||
обычную авторизацию.
|
||||
В случае получения какой-либо предусмотренной ошибки, следует заново запросить пароль пользователя и произвести обычную авторизацию.
|
||||
|
||||
Успешный ответ:
|
||||
|
||||
@ -150,8 +147,7 @@
|
||||
|
||||
.. function:: POST /auth/validate
|
||||
|
||||
Этот запрос позволяет проверить валиден ли указанный accessToken или нет. Этот запрос не обновляет токен и его время
|
||||
жизни, а только позволяет удостовериться, что он ещё действительный.
|
||||
Этот запрос позволяет проверить валиден ли указанный accessToken или нет. Этот запрос не обновляет токен и его время жизни, а только позволяет удостовериться, что он ещё действительный.
|
||||
|
||||
:param string accessToken: Токен доступа, полученный после авторизации.
|
||||
|
||||
@ -160,7 +156,7 @@
|
||||
.. code-block:: javascript
|
||||
|
||||
{
|
||||
"error: "ForbiddenOperationException",
|
||||
"error": "ForbiddenOperationException",
|
||||
"errorMessage": "Token expired."
|
||||
}
|
||||
|
||||
@ -175,8 +171,7 @@
|
||||
|
||||
.. function:: POST /auth/invalidate
|
||||
|
||||
Запрос позволяет инвалидировать accessToken. В случае, если переданный токен не удастся найти в хранилище токенов,
|
||||
ошибка не будет сгенерирована и вы получите успешный ответ.
|
||||
Запрос позволяет инвалидировать accessToken. В случае, если переданный токен не удастся найти в хранилище токенов, ошибка не будет сгенерирована и вы получите успешный ответ.
|
||||
|
||||
Входные параметры:
|
||||
|
||||
@ -188,18 +183,14 @@
|
||||
Авторизация на сервере
|
||||
======================
|
||||
|
||||
Эти запросы выполняются непосредственно клиентом и сервером при помощи внутреннего кода или библиотеки authlib
|
||||
(начиная с версии 1.7.2). Они актуальны только в том случае, если вы уже произвели авторизацию и запустили игру с валидным
|
||||
accessToken. Вам остаётся только заменить пути внутри игры/библиотеки на привидённые ниже пути.
|
||||
Эти запросы выполняются непосредственно клиентом и сервером при помощи внутреннего кода или библиотеки authlib (начиная с версии 1.7.2). Они актуальны только в том случае, если вы уже произвели авторизацию и запустили игру с валидным accessToken. Вам остаётся только заменить пути внутри игры/библиотеки на приведённые ниже пути.
|
||||
|
||||
Поскольку непосредственно изменить что-либо в работе authlib или игры вы не можете, здесь не приводятся передаваемые значения
|
||||
и ответы сервера. При необходимости вы сможете найти эту информацию самостоятельно в интернете.
|
||||
Поскольку непосредственно изменить что-либо в работе authlib или игры вы не можете, здесь не приводятся передаваемые значения и ответы сервера. При необходимости вы сможете найти эту информацию самостоятельно в интернете.
|
||||
|
||||
Через authlib
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. important:: Эта часть документации описывает запросы, выполняемые через authlib в версии игры 1.7.2+. Для более старых
|
||||
версий смотрите раздел ниже.
|
||||
.. important:: Эта часть документации описывает запросы, выполняемые через authlib в версии игры 1.7.2+. Для более старых версий смотрите раздел ниже.
|
||||
|
||||
Все запросы из этой категории выполняются на подуровень /session. Перед каждым из запросов указан тип отправляемого запроса.
|
||||
|
||||
@ -209,21 +200,14 @@ accessToken. Вам остаётся только заменить пути вн
|
||||
|
||||
.. function:: GET /session/hasJoined
|
||||
|
||||
Запрос на этот URL выполняет сервер с online-mode=true после того, как клиент, пытающийся к нему подключится, успешно
|
||||
выполнит join запрос.
|
||||
Запрос на этот URL выполняет сервер с online-mode=true после того, как клиент, пытающийся к нему подключится, успешно выполнит join запрос.
|
||||
|
||||
.. attention:: Внутри тела ответа есть параметр **properties**, который, в свою очередь, содержит поле **value** с
|
||||
закодированной в ней base64 строкой. В оригинальной системе авторизации данные зашифрованы с помощью
|
||||
приватного ключа и расшифровывались на клиенте с помощью публичного.
|
||||
|
||||
Ely, в свою очередь, **не выполняет шифрацию вовсе**, поэтому вам необходимо отключить проверку подписи в
|
||||
библиотеке authlib. В противном случае текстуры всегда будут признаваться невалидными.
|
||||
.. attention:: Внутри тела ответа есть параметр **properties**, который, в свою очередь, содержит поле **value** с закодированной в ней base64 строкой. В оригинальной системе авторизации данные зашифрованы с помощью приватного ключа и расшифровывались на клиенте с помощью публичного. Ely, в свою очередь, **не выполняет шифрацию вовсе**, поэтому вам необходимо отключить проверку подписи в библиотеке authlib. В противном случае текстуры всегда будут признаваться невалидными.
|
||||
|
||||
Для старых версий
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. important:: Эта часть документации описывает запросы, выполняемые более старыми версиями Minecraft, когда не применялась
|
||||
библиотека authlib. Это все версии, младше версии 1.7.2.
|
||||
.. important:: Эта часть документации описывает запросы, выполняемые более старыми версиями Minecraft, когда не применялась библиотека authlib. Это все версии, младше версии 1.7.2.
|
||||
|
||||
Все запросы из этой категории выполняются на подуровень /session/legacy. Перед каждым из запросов указан тип отправляемого запроса.
|
||||
|
||||
@ -235,72 +219,55 @@ accessToken. Вам остаётся только заменить пути вн
|
||||
|
||||
.. function:: GET /session/legacy/hasJoined
|
||||
|
||||
Запрос на этот URL выполняет сервер с online-mode=true после того, как клиент, пытающийся к нему подключится, успешно
|
||||
выполнит join запрос.
|
||||
Запрос на этот URL выполняет сервер с online-mode=true после того, как клиент, пытающийся к нему подключится, успешно выполнит join запрос.
|
||||
|
||||
Важно не потерять GET параметр **?user=** в конце обоих запросов, чтобы получились следующие URL:
|
||||
``http://minecraft.ely.by/session/legacy/hasJoined?user=``.
|
||||
Важно не потерять GET параметр **?user=** в конце обоих запросов, чтобы получились следующие URL: ``http://minecraft.ely.by/session/legacy/hasJoined?user=``.
|
||||
|
||||
Одиночная игра
|
||||
==============
|
||||
|
||||
По сути, одиночная игра - это локальный сервер, созданный для одного игрока. По крайней мере это так, начиная с версии 1.6,
|
||||
в которой и был представлен механизм локальных серверов.
|
||||
По сути, одиночная игра - это локальный сервер, созданный для одного игрока. По крайней мере это так, начиная с версии 1.6, в которой и был представлен механизм локальных серверов.
|
||||
|
||||
Тем не менее, описанный ниже запрос актуален только для Minecraft 1.7.6+, когда для загрузки скинов стала использоваться
|
||||
так же authlib.
|
||||
Тем не менее, описанный ниже запрос актуален только для Minecraft 1.7.6+, когда для загрузки скинов стала использоваться так же Authlib.
|
||||
|
||||
.. _profile-request:
|
||||
|
||||
.. function:: GET /session/profile/{uuid}
|
||||
|
||||
Запрос на этот URL выполняется клиентом в одиночной игре на локальном сервере (созданном посредством самой игры).
|
||||
В URL передаётся UUID пользователя, с которым был запущен клиент, а в ответ получается информация о текстурах игрока
|
||||
в таком же формате, как и при hasJoined запросе.
|
||||
Запрос на этот URL выполняется клиентом в одиночной игре на локальном сервере (созданном посредством самой игры). В URL передаётся UUID пользователя, с которым был запущен клиент, а в ответ получается информация о текстурах игрока в таком же формате, как и при hasJoined запросе.
|
||||
|
||||
Готовые библиотеки authlib
|
||||
==========================
|
||||
|
||||
.. attention:: Ely.by поддрживает библиотеку authlib-injector. Это наиболее простой и универсальный способ установки системы авторизации в игру и игровые сервера. За подробностями обратитесь в :doc:`соответствующий раздел документации <authlib-injector>`.
|
||||
.. attention:: Ely.by поддерживает библиотеку authlib-injector. Это наиболее простой и универсальный способ установки системы авторизации в игру и игровые сервера. За подробностями обратитесь в :doc:`соответствующий раздел документации <authlib-injector>`.
|
||||
|
||||
Поскольку самостоятельная реализация связана с трудностями поиска исходников, подключения зависимостей и в конце-концов
|
||||
с процессом компиляции, на `странице загрузок нашей системы скинов <//ely.by/load>`_ вы можете загрузить уже
|
||||
готовые библиотеки со всеми необходимыми изменениями. Выберите в выпадающем списке необходимую версию и следуйте
|
||||
инструкции по установке, размещённой на той же странице ниже.
|
||||
Поскольку самостоятельная реализация связана с трудностями поиска исходников, подключения зависимостей и в конце-концов с процессом компиляции, на `странице загрузок нашей системы скинов <https://ely.by/load>`_ вы можете загрузить уже готовые библиотеки со всеми необходимыми изменениями. Выберите в выпадающем списке необходимую версию и следуйте инструкции по установке, размещённой на той же странице ниже.
|
||||
|
||||
В более ранних версиях игры система скинов находилась внутри игрового клиента, так что библиотеки ниже обеспечивают
|
||||
лишь авторизацию:
|
||||
В более ранних версиях игры система скинов находилась внутри игрового клиента, так что библиотеки ниже обеспечивают лишь авторизацию:
|
||||
|
||||
* Minecraft 1.7.5 - :download:`authlib 1.3.1 <../_static/minecraft-auth/authlib/authlib-1.3.1.jar>`
|
||||
* Minecraft 1.7.5 - :download:`authlib 1.3.1 <files/authlib/authlib-1.3.1.jar>`
|
||||
|
||||
* Minecraft 1.7.2 - :download:`authlib 1.3 <../_static/minecraft-auth/authlib/authlib-1.3.jar>`
|
||||
* Minecraft 1.7.2 - :download:`authlib 1.3 <files/authlib/authlib-1.3.jar>`
|
||||
|
||||
Для установки вам необходимо заменить оригинальную библиотеку, располагающуюся по пути
|
||||
``<директория установки minecraft>/libraries/com/mojang/authlib/``. Убедитесь в том, что версии скачанного и заменяемого
|
||||
файлов совпадают.
|
||||
Для установки вам необходимо заменить оригинальную библиотеку, располагающуюся по пути ``<директория установки minecraft>/libraries/com/mojang/authlib/``. Убедитесь в том, что версии скачанного и заменяемого файлов совпадают.
|
||||
|
||||
.. _install-server:
|
||||
|
||||
Установка authlib на сервер
|
||||
===========================
|
||||
|
||||
Сервер также использует authlib для выполнения авторизации игрока, поэтому соответствующие изменения должны быть
|
||||
также применены и к нему. Ниже приведены инструкции по установки authlib для различных реализаций сервера Minecraft.
|
||||
Сервер также использует authlib для выполнения авторизации игрока, поэтому соответствующие изменения должны быть также применены и к нему. Ниже приведены инструкции по установки authlib для различных реализаций сервера Minecraft.
|
||||
|
||||
.. note:: Если ни одна из приведённых ниже инструкций не подошла для вашей реализации сервера, пожалуйста,
|
||||
создайте `новый issue <https://github.com/elyby/docs/issues/new>`_ и мы допишем инструкцию для вашего сервера.
|
||||
.. note:: Если ни одна из приведённых ниже инструкций не подошла для вашей реализации сервера, пожалуйста, создайте `новый issue <https://github.com/elyby/docs/issues/new>`_ и мы допишем инструкцию для вашего сервера.
|
||||
|
||||
.. _vanilla:
|
||||
|
||||
Оригинальный сервер
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
С помощью архиватора откройте файл сервера ``minecraft_server.ВЕРСИЯ.jar``. Таким же образом откройте архив с
|
||||
authlib для соответствующей версии сервера. Перед вами будет два окна: одно с файлами сервера, другое с файлами authlib.
|
||||
Вам необходимо "перетащить" из архива с authlib все файлы и папки, **за исключением директории META-INF**, и подтвердить
|
||||
замену.
|
||||
С помощью архиватора откройте файл сервера ``minecraft_server.ВЕРСИЯ.jar``. Таким же образом откройте архив с authlib для соответствующей версии сервера. Перед вами будет два окна: одно с файлами сервера, другое с файлами authlib. Вам необходимо "перетащить" из архива с authlib все файлы и папки, **за исключением директории META-INF**, и подтвердить замену.
|
||||
|
||||
.. figure:: ../_static/minecraft-auth/authlib-install.png
|
||||
.. figure:: images/minecraft-auth/authlib-install.png
|
||||
:align: center
|
||||
:alt: Процесс установки Authlib
|
||||
|
||||
@ -311,10 +278,7 @@ authlib для соответствующей версии сервера. Пе
|
||||
Bukkit/Spigot
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Сперва выполните установку, как она описана для `оригинального сервера <#vanilla>`_. Затем скачайте библиотеки
|
||||
`commons-io <https://repo1.maven.org/maven2/commons-io/commons-io/2.5/commons-io-2.5.jar>`_ и
|
||||
`commons-lang3 <https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar>`_,
|
||||
после чего аналогичным с authlib образом последовательно переместите содержимое скачанных архивов в файлы сервера.
|
||||
Сперва выполните установку, как она описана для `оригинального сервера <#vanilla>`_. Затем скачайте библиотеки `commons-io <https://repo1.maven.org/maven2/commons-io/commons-io/2.5/commons-io-2.5.jar>`_ и `commons-lang3 <https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar>`_, после чего аналогичным с authlib образом последовательно переместите содержимое скачанных архивов в файлы сервера.
|
||||
|
||||
Forge/Sponge
|
||||
~~~~~~~~~~~~
|
||||
@ -330,9 +294,7 @@ Forge/Sponge
|
||||
Paper (PaperSpigot)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Установка производится по аналогии с `Bukkit/Spigot <#bukkit-spigot>`_ в файл ``cache/patched-ВЕРСИЯ.jar``.
|
||||
После внесения изменений, запускать сервер нужно через jar-файл из директории ``cache``, поскольку в противном случае
|
||||
**Paper восстановит исходное состояние файла**:
|
||||
Установка производится по аналогии с `Bukkit/Spigot <#bukkit-spigot>`_ в файл ``cache/patched-ВЕРСИЯ.jar``. После внесения изменений, запускать сервер нужно через jar-файл из директории ``cache``, поскольку в противном случае **Paper восстановит исходное состояние файла**:
|
||||
|
||||
| До: ``java -jar paper-ВЕРСИЯ-БИЛД.jar``
|
||||
| После: ``java -jar cache/patched-ВЕРСИЯ.jar``
|
||||
@ -356,13 +318,13 @@ BungeeCord
|
||||
|
||||
#. Откройте распакованный файл в программе InClassTranslator и замените в нём строку ``https://sessionserver.mojang.com/session/minecraft/hasJoined?username=`` на ``https://authserver.ely.by/session/hasJoined?username=``, как показано на рисунке ниже:
|
||||
|
||||
.. figure:: ../_static/minecraft-auth/bungeecord_inclasstranslator.png
|
||||
.. figure:: images/minecraft-auth/bungeecord_inclasstranslator.png
|
||||
:align: center
|
||||
:alt: Редактирование в InClassTranslator
|
||||
|
||||
#. Сохраните изменения и перетащите измененный файл обратно в архив сервера. Подтвердите замену.
|
||||
|
||||
.. figure:: ../_static/minecraft-auth/bungeecord_move.png
|
||||
.. figure:: images/minecraft-auth/bungeecord_move.png
|
||||
:align: center
|
||||
:alt: Перетаскивание отредактированного файла назад в архив
|
||||
|
||||
@ -375,12 +337,9 @@ BungeeCord
|
||||
Установка на версии ниже 1.7.2
|
||||
==============================
|
||||
|
||||
Для более старых версий существует достаточно большое многообразие различных случаев, раскрыть которые в этой документации
|
||||
не представляется возможным. Вся установка заключается в замене определённых строк в определённых классах через
|
||||
InClassTranslator.
|
||||
Для более старых версий существует достаточно большое многообразие различных случаев, раскрыть которые в этой документации не представляется возможным. Вся установка заключается в замене определённых строк в определённых классах через InClassTranslator.
|
||||
|
||||
На форуме RuBukkit есть отличный пост, в котором собрана вся нужна информация по именам классов на различных версиях
|
||||
Minecraft. Переписывать его сюда не имеет смысла, так что просто перейдите на его страницу и найдите нужную версию.
|
||||
На форуме RuBukkit есть отличный пост, в котором собрана вся нужна информация по именам классов на различных версиях Minecraft. Переписывать его сюда не имеет смысла, так что просто перейдите на его страницу и найдите нужную версию.
|
||||
|
||||
|rubukkit_link|.
|
||||
|
||||
@ -394,21 +353,19 @@ Minecraft. Переписывать его сюда не имеет смысла
|
||||
|
||||
Предположим, что вы хотите установить авторизацию на сервер версии 1.5.2.
|
||||
|
||||
Сначала вы переходите по вышепривидённой ссылке, выбираете нужную версию (1.5.2) и видите список классов:
|
||||
Сначала вы переходите по вышеприведённой ссылке, выбираете нужную версию (1.5.2) и видите список классов:
|
||||
|
||||
* **bdk.class** - путь до joinserver
|
||||
|
||||
* **jg.class** - путь до checkserver
|
||||
|
||||
Затем вы должны взять .jar файл клиента и открыть его любым архиватором. После чего вам необходимо найти файл **bdk.class**.
|
||||
Для этого удобно воспользоваться поиском.
|
||||
Затем вы должны взять .jar файл клиента и открыть его любым архиватором. После чего вам необходимо найти файл **bdk.class**. Для этого удобно воспользоваться поиском.
|
||||
|
||||
После того, как вы нашли файл, его нужно извлечь из архива - просто перетащите его оттуда в удобную для вас дирикторию.
|
||||
|
||||
Дальше запустите InClassTranslator и в нём откройте этот класс. Слева будет список найденных в файле строк, которые вы
|
||||
можете изменить. Нужно заменить только строку, отвечающую за запрос на подключение к серверу:
|
||||
Дальше запустите InClassTranslator и в нём откройте этот класс. Слева будет список найденных в файле строк, которые вы можете изменить. Нужно заменить только строку, отвечающую за запрос на подключение к серверу:
|
||||
|
||||
.. figure:: ../_static/minecraft-auth/installing_by_inclasstranslator.png
|
||||
.. figure:: images/minecraft-auth/installing_by_inclasstranslator.png
|
||||
:align: center
|
||||
:alt: Порядок редактирования: выбрать нужную строку, изменить, сохранить.
|
||||
|
||||
@ -418,5 +375,4 @@ Minecraft. Переписывать его сюда не имеет смысла
|
||||
|
||||
-----------------------
|
||||
|
||||
После этих действий вам нужно в настройках включить online-mode=true и сервер станет пускать на себя только тех игроков,
|
||||
которые будут авторизованы через Ely.by.
|
||||
После этих действий вам нужно в настройках включить online-mode=true и сервер станет пускать на себя только тех игроков, которые будут авторизованы через Ely.by.
|
@ -1,8 +0,0 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=/ru/oauth.html" />
|
||||
<script>
|
||||
window.location.href = '/ru/oauth.html'
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -1,24 +1,18 @@
|
||||
Авторизация по протоколу OAuth2
|
||||
-------------------------------
|
||||
|
||||
На этой странице вы найдёте информацию о реализации авторизации по протоколу OAuth2 на вашем проекте через сервис
|
||||
Аккаунты Ely.by. Реализация этого протокола позволяет вашим пользователям производить авторизацию с использованием
|
||||
своего аккаунта Ely.by.
|
||||
На этой странице вы найдёте информацию о реализации авторизации по протоколу OAuth2 на вашем проекте через сервис Аккаунты Ely.by. Реализация этого протокола позволяет вашим пользователям производить авторизацию с использованием своего аккаунта Ely.by.
|
||||
|
||||
Регистрация приложения
|
||||
======================
|
||||
|
||||
Для начала вам необходимо `создать новое приложение <https://account.ely.by/dev/applications/new>`_. Выберите тип
|
||||
приложения **Веб‑сайт**. В качестве *адреса переадресации* можно указать только домен, но для повышения безопасности
|
||||
лучше использовать полный путь переадресации. Примеры допустимых адресов:
|
||||
Для начала вам необходимо `создать новое приложение <https://account.ely.by/dev/applications/new>`_. Выберите тип приложения **Веб‑сайт**. В качестве *адреса переадресации* можно указать только домен, но для повышения безопасности лучше использовать полный путь переадресации. Примеры допустимых адресов:
|
||||
|
||||
* :samp:`http://site.com`
|
||||
* :samp:`http://site.com/oauth/ely`
|
||||
* :samp:`http://site.com/oauth.php?provider=ely`
|
||||
* ``http://site.com``
|
||||
* ``http://site.com/oauth/ely``
|
||||
* ``http://site.com/oauth.php?provider=ely``
|
||||
|
||||
После успешного добавления приложения вы попадёте на страницу со списком всех ваших приложений. Кликнув по названию
|
||||
приложения вы увидите его идентификатор ``clientId`` и секрет ``clientSecret``. Они буду использоваться на
|
||||
следующих шагах.
|
||||
После успешного добавления приложения вы попадёте на страницу со списком всех ваших приложений. Кликнув по названию приложения вы увидите его идентификатор ``clientId`` и секрет ``clientSecret``. Они буду использоваться на следующих шагах.
|
||||
|
||||
Инициализация авторизации
|
||||
=========================
|
||||
@ -37,34 +31,29 @@
|
||||
- Пример значения
|
||||
- Описание
|
||||
* - *clientId*
|
||||
- :samp:`ely`
|
||||
- ``ely``
|
||||
- **Обязательное**. ClientId, полученный при регистрации.
|
||||
* - *redirect_uri*
|
||||
- :samp:`http://site.com/oauth.php`
|
||||
- ``http://site.com/oauth.php``
|
||||
- **Обязательное**. Адрес обратной переадресации, совпадающий с адресом, указанным при регистрации приложения
|
||||
* - *response_type*
|
||||
- :samp:`code`
|
||||
- ``code``
|
||||
- **Обязательное**. Тип ответа. На данный момент поддерживается только ``code``.
|
||||
* - *scope*
|
||||
- :samp:`account_info account_email`
|
||||
- **Обязательное**. Перечень разрешений, доступ к которым вы хотите получить, разделённые пробелом. Смотрите все
|
||||
доступные права в `разделе ниже <#available-scopes>`_.
|
||||
- ``account_info account_email``
|
||||
- **Обязательное**. Перечень разрешений, доступ к которым вы хотите получить, разделённые пробелом. Смотрите все доступные права в `разделе ниже <#available-scopes>`_.
|
||||
* - *state*
|
||||
- :samp:`isfvubuysdboinsbdfvit`
|
||||
- Случайно сгенерированная строка. Используется для увеличения безопасности в качестве идентификатора сессии. Будет
|
||||
возвращена в неизменённом виде после завершения авторизации.
|
||||
- ``isfvubuysdboinsbdfvit``
|
||||
- Случайно сгенерированная строка. Используется для увеличения безопасности в качестве идентификатора сессии. Будет возвращена в неизменённом виде после завершения авторизации.
|
||||
* - *description*
|
||||
- :samp:`यो अनुप्रयोग विवरण`
|
||||
- Если ваше приложение доступно на нескольких языках, то используя это поле вы можете переопределить стандартное
|
||||
описание в соответствии с предпочтительным языком пользователя.
|
||||
- ``यो अनुप्रयोग विवरण``
|
||||
- Если ваше приложение доступно на нескольких языках, то используя это поле вы можете переопределить стандартное описание в соответствии с предпочтительным языком пользователя.
|
||||
* - *prompt*
|
||||
- :samp:`consent` или :samp:`select_account`
|
||||
- Принудительно отобразить запрос прав (``consent``) или принудительно запросить выбор аккаунта
|
||||
(``select_account``).
|
||||
- ``consent`` или ``select_account``
|
||||
- Принудительно отобразить запрос прав (``consent``) или принудительно запросить выбор аккаунта (``select_account``).
|
||||
* - *login_hint*
|
||||
- :samp:`erickskrauch` или :samp:`erickskrauch@ely.by`
|
||||
- Если у пользователя есть несколько аккаунтов, то указав этот в этом параметре username или email пользователя вы
|
||||
автоматически выберете аккаунт за него. Это полезно в случае повторного входа, когда токен истёк.
|
||||
- ``erickskrauch`` или ``erickskrauch@ely.by``
|
||||
- Если у пользователя есть несколько аккаунтов, то указав этот в этом параметре username или E-mail пользователя вы автоматически выберете аккаунт за него. Это полезно в случае повторного входа, когда токен истёк.
|
||||
|
||||
.. _available_scopes:
|
||||
.. list-table:: Перечень доступных scopes
|
||||
@ -76,12 +65,11 @@
|
||||
* - **account_email**
|
||||
- В ответе на запрос информации о пользователе будет также присутствовать его email.
|
||||
* - **offline_access**
|
||||
- Вместе с ``access_token`` вы также получите и ``refresh_token``. Смотрите подробнее
|
||||
`соответствующем разделе <#refresh-token-grant>`_.
|
||||
- Вместе с ``access_token`` вы также получите и ``refresh_token``. Смотрите подробнее `соответствующем разделе <#refresh-token-grant>`_.
|
||||
* - **minecraft_server_session**
|
||||
- ``access_token`` можно будет использовать в качестве сессии для Minecraft.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Сформировав ссылку, разместите её в вашем шаблоне:
|
||||
|
||||
@ -89,11 +77,9 @@
|
||||
|
||||
<a href="<ваша_ссылка>">Войти через Ely.by</a>
|
||||
|
||||
По нажатию на ссылку, пользователь попадёт на нашу страницу авторизации, откуда после он будет перенаправлен обратно
|
||||
по адресу, указанному в параметре ``redirect_uri``.
|
||||
По нажатию на ссылку, пользователь попадёт на нашу страницу авторизации, откуда после он будет перенаправлен обратно по адресу, указанному в параметре ``redirect_uri``.
|
||||
|
||||
Обратная переадресация выполняется в виде ``<redirect_uri>?code=<код авторизации>&state=<state>`` для успешной
|
||||
авторизации и ``<redirect_uri?error=<идентификатор ошибки>&error_message=<описание ошибки>`` для неудачной.
|
||||
Обратная переадресация выполняется в виде ``<redirect_uri>?code=<код авторизации>&state=<state>`` для успешной авторизации и ``<redirect_uri?error=<идентификатор ошибки>&error_message=<описание ошибки>`` для неудачной.
|
||||
|
||||
Пример успешного и неудачного редиректов:
|
||||
|
||||
@ -107,8 +93,7 @@
|
||||
Обмен кода на ключ
|
||||
==================
|
||||
|
||||
После получения кода авторизации (``auth_code``), вам необходимо обменять его на ключ авторизации (``access_key``).
|
||||
Для этого необходимо выполнить POST запрос на URL:
|
||||
После получения кода авторизации (``auth_code``), вам необходимо обменять его на ключ авторизации (``access_key``). Для этого необходимо выполнить POST запрос на URL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@ -176,8 +161,7 @@
|
||||
Ответ сервера
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
В случае успешного запроса в теле ответа будет находиться результат обмена кода авторизации на ``access_token``.
|
||||
Данные являются JSON документом и могут быть легко интерпретированы средствами используемого языка программирования.
|
||||
В случае успешного запроса в теле ответа будет находиться результат обмена кода авторизации на ``access_token``. Данные являются JSON документом и могут быть легко интерпретированы средствами используемого языка программирования.
|
||||
|
||||
Тело JSON документа содержит следующие поля:
|
||||
|
||||
@ -190,14 +174,12 @@
|
||||
"expires_in": 86400 // Количество секунд, на которое выдан токен
|
||||
}
|
||||
|
||||
На этом процедура авторизации закончена. Полученный ``access_token`` может быть использован для получения информации о
|
||||
пользователе и взаимодействия с нашим API.
|
||||
На этом процедура авторизации закончена. Полученный ``access_token`` может быть использован для получения информации о пользователе и взаимодействия с нашим API.
|
||||
|
||||
Получение информации о пользователе
|
||||
===================================
|
||||
|
||||
Если полученный токен имеет scope ``account_info``, то вы можете запросить информацию об аккаунте пользователя. Для
|
||||
этого необходимо отправить запрос на URL:
|
||||
Если полученный токен имеет scope ``account_info``, то вы можете запросить информацию об аккаунте пользователя. Для этого необходимо отправить запрос на URL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@ -235,23 +217,18 @@
|
||||
"email": "erickskrauch@ely.by"
|
||||
}
|
||||
|
||||
Обратите внимание, что поле ``email`` будет присутствовать лишь в том случае, когда был запрошен scope
|
||||
``account_email``.
|
||||
Обратите внимание, что поле ``email`` будет присутствовать лишь в том случае, когда был запрошен scope ``account_email``.
|
||||
|
||||
.. note:: В ходе дальнейшего развития сервиса, количество возвращаемых полей может увеличиться, но уже существующие
|
||||
останутся теми же.
|
||||
.. note:: В ходе дальнейшего развития сервиса, количество возвращаемых полей может увеличиться, но уже существующие останутся теми же.
|
||||
|
||||
.. _refresh-token-grant:
|
||||
|
||||
Обновление токена доступа
|
||||
=========================
|
||||
|
||||
Если при выполнении авторизации вами было запрошено право на получение scope ``offline_access``, то вместе с
|
||||
``access_token`` вы также получите и ``refresh_token``. Данный токен не истекает и может быть использован для получения
|
||||
нового токена доступа, когда он истечёт.
|
||||
Если при выполнении авторизации вами было запрошено право на получение scope ``offline_access``, то вместе с ``access_token`` вы также получите и ``refresh_token``. Данный токен не истекает и может быть использован для получения нового токена доступа, когда он истечёт.
|
||||
|
||||
Для выполнения операции обновления токена необходимо отправить POST запрос на тот же URL, что использовался и
|
||||
`при обмене кода на ключ доступа <#authorization-code-grant>`_, но со следующими параметрами:
|
||||
Для выполнения операции обновления токена необходимо отправить POST запрос на тот же URL, что использовался и `при обмене кода на ключ доступа <#authorization-code-grant>`_, но со следующими параметрами:
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
@ -262,8 +239,7 @@
|
||||
* - ``client_secret``
|
||||
- ClientSecret, полученный при регистрации приложения.
|
||||
* - ``scope``
|
||||
- Те же scope, что были запрошены и при получении начального токена доступа. Попытка запросить большее количество
|
||||
прав приведёт к ошибке.
|
||||
- Те же scope, что были запрошены и при получении начального токена доступа. Попытка запросить большее количество прав приведёт к ошибке.
|
||||
* - ``refresh_token``
|
||||
- Непосредственно токен, полученный вместе с начальным токеном доступа.
|
||||
|
||||
@ -291,66 +267,56 @@
|
||||
$result = json_decode(curl_exec($curl), true);
|
||||
curl_close($curl);
|
||||
|
||||
В качестве ответа будет точно такое же тело, какое было получено в результате
|
||||
`обмена кода на ключ доступа <#authorization-code-grant-response>`_. Поле ``refresh_token`` будет отсутствовать.
|
||||
В качестве ответа будет точно такое же тело, какое было получено в результате `обмена кода на ключ доступа <#authorization-code-grant-response>`_. Поле ``refresh_token`` будет отсутствовать.
|
||||
|
||||
Готовые библиотеки
|
||||
==================
|
||||
|
||||
Более простым способом будет использовать уже готовую библиотеку, которой будет необходимо передать лишь регистрационные
|
||||
параметры. Ниже перечислены библиотеки для различных языков программирования. Вы можете дополнить этот список своей
|
||||
библиотекой.
|
||||
Более простым способом будет использовать уже готовую библиотеку, которой будет необходимо передать лишь регистрационные параметры. Ниже перечислены библиотеки для различных языков программирования. Вы можете дополнить этот список своей библиотекой.
|
||||
|
||||
* **PHP**:
|
||||
|
||||
- [Official] https://github.com/elyby/league-oauth2-provider
|
||||
- [Официальная] https://github.com/elyby/league-oauth2-provider
|
||||
|
||||
* **Ruby**:
|
||||
|
||||
- [Official] https://github.com/elyby/omniauth-ely
|
||||
- [Официальная] https://github.com/elyby/omniauth-ely
|
||||
|
||||
Возможные ошибки
|
||||
================
|
||||
|
||||
Ниже приведены стандартные ошибки, которые вы можете получить в случае неправильной передачи данных на сервер
|
||||
авторизации. Если вы столкнулись с ошибкой, не описанной в этой документации, пожалуйста, сообщите о ней через
|
||||
`форму обратной связи <http://ely.by/site/contact>`_.
|
||||
Ниже приведены стандартные ошибки, которые вы можете получить в случае неправильной передачи данных на сервер авторизации. Если вы столкнулись с ошибкой, не описанной в этой документации, пожалуйста, сообщите о ней через `форму обратной связи <https://ely.by/site/contact>`_.
|
||||
|
||||
.. _auth-start-errors:
|
||||
|
||||
Ошибки при инициализации авторизации
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Этот раздел описывает ошибки, отображаемые при переадресации пользователя с вашего сайта на нашу страницу инициализации
|
||||
авторизации.
|
||||
Этот раздел описывает ошибки, отображаемые при переадресации пользователя с вашего сайта на нашу страницу инициализации авторизации.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid request ({parameter} required).
|
||||
|
||||
Данная ошибка означает, что вы передали не все необходимые параметры. Чтобы решить эту ошибку просто добавьте
|
||||
недостающий параметр.
|
||||
Данная ошибка означает, что вы передали не все необходимые параметры. Чтобы решить эту ошибку просто добавьте недостающий параметр.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid response type '{invalid_response_type_value}'.
|
||||
|
||||
Данная ошибка означает, что вы передали неподдерживаемый тип ``response_type``. На данный момент поддерживается только
|
||||
значение ``code``.
|
||||
Данная ошибка означает, что вы передали неподдерживаемый тип ``response_type``. На данный момент поддерживается только значение ``code``.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Invalid scope '{invalid_scope}'.
|
||||
|
||||
Ошибка указывает на то, что было запрошено неизвестный ``scope``. Убедитесь, что вы запрашиваете
|
||||
`поддерживаемые права <#available-scopes>`_.
|
||||
Ошибка указывает на то, что было запрошено неизвестный ``scope``. Убедитесь, что вы запрашиваете `поддерживаемые права <#available-scopes>`_.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Can not find application you are trying to authorize.
|
||||
|
||||
Данная ошибка говорит о том, что переданные параметры не соответствуют ни одному из зарегистрированных приложений.
|
||||
Для решения проблемы исправьте ваши значения ``client_id`` и ``redirect_uri``.
|
||||
Данная ошибка говорит о том, что переданные параметры не соответствуют ни одному из зарегистрированных приложений. Для решения проблемы исправьте ваши значения ``client_id`` и ``redirect_uri``.
|
||||
|
||||
.. _issue-token-errors:
|
||||
|
||||
@ -366,8 +332,7 @@
|
||||
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"code\" parameter."
|
||||
}
|
||||
|
||||
В поле ``error`` находится системный идентификатор ошибки, в ``error_description`` — описание ошибки на английском
|
||||
языке.
|
||||
В поле ``error`` находится системный идентификатор ошибки, в ``error_description`` — описание ошибки на английском языке.
|
||||
|
||||
**Возможные значения error:**
|
||||
|
||||
@ -378,17 +343,14 @@
|
||||
* - ``invalid_request``
|
||||
- Переданы не все необходимые параметры запроса или значение ``code`` не был найден в базе выданных кодов.
|
||||
* - ``unsupported_grant_type``
|
||||
- Данная ошибка сигнализирует о том, что вы попытались произвести авторизацию по неизвестному для нашего OAuth2
|
||||
сервера типу Grant.
|
||||
- Данная ошибка сигнализирует о том, что вы попытались произвести авторизацию по неизвестному для нашего OAuth2 сервера типу Grant.
|
||||
* - ``invalid_client``
|
||||
- Эта ошибка возникает в случае, когда трио значений ``client_id``, ``client_secret`` и ``redirect_uri`` не совпали
|
||||
ни с одним из зарегистрированных приложений.
|
||||
- Эта ошибка возникает в случае, когда трио значений ``client_id``, ``client_secret`` и ``redirect_uri`` не совпали ни с одним из зарегистрированных приложений.
|
||||
|
||||
Ошибки при запросе информации о пользователе
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Ответ со статусом ``401`` указывает на то, что заголовок ``Authorization`` не присутствует в запросе или его значение
|
||||
сформировано неверно. Тело ответа будет следующим:
|
||||
Ответ со статусом ``401`` указывает на то, что заголовок ``Authorization`` не присутствует в запросе или его значение сформировано неверно. Тело ответа будет следующим:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@ -398,8 +360,7 @@
|
||||
"message": "Your request was made with invalid credentials."
|
||||
}
|
||||
|
||||
Ответ со статусом ``403`` сигнализирует о том, что переданный в заголовке ``Authorization`` токен не содержит scope
|
||||
``account_info`` или он истёк. Получаемый ответ будет иметь следующий формат:
|
||||
Ответ со статусом ``403`` сигнализирует о том, что переданный в заголовке ``Authorization`` токен не содержит scope ``account_info`` или он истёк. Получаемый ответ будет иметь следующий формат:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@ -412,15 +373,13 @@
|
||||
Ошибки при обновлении токена доступа
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
При выполнении обновления токена доступа вам могут встретиться те же ошибки, что и при
|
||||
`обмене кода на ключ доступа <#issue-token-errors>`_, а также несколько новых:
|
||||
При выполнении обновления токена доступа вам могут встретиться те же ошибки, что и при `обмене кода на ключ доступа <#issue-token-errors>`_, а также несколько новых:
|
||||
|
||||
.. list-table::
|
||||
:widths: 1 99
|
||||
:header-rows: 0
|
||||
|
||||
* - ``invalid_request``
|
||||
- Переданы не все необходимые параметры запроса или значение ``refresh_token`` не был найден в базе выданных
|
||||
токенов.
|
||||
- Переданы не все необходимые параметры запроса или значение ``refresh_token`` не был найден в базе выданных токенов.
|
||||
* - ``invalid_scope``
|
||||
- Были перечислены неподдерживаемые scope или запрошено больше, чем было у изначального токена.
|
@ -1,8 +0,0 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=/ru/skins-system.html" />
|
||||
<script>
|
||||
window.location.href = '/ru/skins-system.html'
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -1,46 +1,36 @@
|
||||
Система скинов
|
||||
--------------
|
||||
|
||||
На этой странице вы найдёте информацию о доступных запросах к сервису системы скинов Ely.by. Вы можете использовать
|
||||
любой из них как дополнительный или основной источник скинов для своего проекта.
|
||||
На этой странице вы найдёте информацию о доступных запросах к сервису системы скинов Ely.by. Вы можете использовать любой из них как дополнительный или основной источник скинов для своего проекта.
|
||||
|
||||
Сервис системы скинов Ely.by обеспечивает `проксирование текстур владельцев лицензии Minecraft <#textures-proxy>`_,
|
||||
что означает, что при использовании этого сервиса игроки будут видеть как скины премиум пользователей Minecraft,
|
||||
так и скины пользователей сервиса Ely.by.
|
||||
Сервис системы скинов Ely.by обеспечивает `проксирование текстур владельцев лицензии Minecraft <#textures-proxy>`_, что означает, что при использовании этого сервиса игроки будут видеть как скины премиум пользователей Minecraft, так и скины пользователей сервиса Ely.by.
|
||||
|
||||
Мы стремимся соответствовать официальной системе скинов и не поддерживаем ушки и HD-скины. Система поддерживает плащи,
|
||||
но не позволяет игрокам самостоятельно их надевать.
|
||||
Мы стремимся соответствовать официальной системе скинов и не поддерживаем ушки и HD-скины. Система поддерживает плащи, но не позволяет игрокам самостоятельно их надевать.
|
||||
|
||||
Если у вас есть предложения по развитию существующего функционала, пожалуйста,
|
||||
`создайте новый Issue <https://github.com/elyby/chrly/issues/new>`_ в
|
||||
`репозитории проекта Chrly <https://github.com/elyby/chrly>`_.
|
||||
Если у вас есть предложения по развитию существующего функционала, пожалуйста, `создайте новый Issue <https://github.com/elyby/chrly/issues/new>`_ в `репозитории проекта Chrly <https://github.com/elyby/chrly>`_.
|
||||
|
||||
.. note:: Вы можете найти более подробную информацию о реализации сервера системы скинов в
|
||||
`репозитории проекта Chrly <https://github.com/elyby/chrly>`_.
|
||||
.. note:: Вы можете найти более подробную информацию о реализации сервера системы скинов в `репозитории проекта Chrly <https://github.com/elyby/chrly>`_.
|
||||
|
||||
URL-адреса запросов
|
||||
===================
|
||||
|
||||
Система скинов размещена на домене :samp:`http://skinsystem.ely.by`.
|
||||
Система скинов размещена на домене ``http://skinsystem.ely.by``.
|
||||
|
||||
Во всех запросах параметр :samp:`nickname` должен быть заменён на ник игрока. Значение не чувствительно к регистру.
|
||||
Во всех запросах параметр ``nickname`` должен быть заменён на ник игрока. Значение не чувствительно к регистру.
|
||||
|
||||
.. _skin-request:
|
||||
.. function:: /skins/{nickname}.png
|
||||
|
||||
URL для загрузки текстуры скина. Расширение :samp:`.png` опционально. Если текстура не будет найдена,
|
||||
сервер вернёт ответ с :samp:`404` статусом.
|
||||
URL для загрузки текстуры скина. Расширение ``.png`` опционально. Если текстура не будет найдена, сервер вернёт ответ с ``404`` статусом.
|
||||
|
||||
.. _cape-request:
|
||||
.. function:: /cloaks/{nickname}.png
|
||||
|
||||
URL для загрузки текстуры плаща. Расширение :samp:`.png` опционально. Если текстура не будет найдена,
|
||||
сервер вернёт ответ с :samp:`404` статусом.
|
||||
URL для загрузки текстуры плаща. Расширение ``.png`` опционально. Если текстура не будет найдена, сервер вернёт ответ с ``404`` статусом.
|
||||
|
||||
.. function:: /textures/{nickname}
|
||||
|
||||
По этому URL вы можете получить текстуры в формате, указанному в поле :samp:`textures` одноимённого property
|
||||
в `ответе на запрос подписанных текстур <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_:
|
||||
По этому URL вы можете получить текстуры в формате, указанному в поле ``textures`` одноимённого property в `ответе на запрос подписанных текстур <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -56,21 +46,15 @@ URL-адреса запросов
|
||||
}
|
||||
}
|
||||
|
||||
В зависимости от доступных игроку текстур могут отсутствовать поля :samp:`SKIN` или :samp:`CAPE`.
|
||||
Если модель скина не является :samp:`slim`, то поле :samp:`metadata` также будет отсутствовать.
|
||||
В зависимости от доступных игроку текстур могут отсутствовать поля ``SKIN`` или ``CAPE``. Если модель скина не является ``slim``, то поле ``metadata`` также будет отсутствовать.
|
||||
|
||||
Если текстуры не будут найдены, сервер вернёт пустой ответ с :samp:`204` статусом.
|
||||
Если текстуры не будут найдены, сервер вернёт пустой ответ с ``204`` статусом.
|
||||
|
||||
.. function:: /profile/{nickname}
|
||||
|
||||
Данный запрос является аналогом запроса
|
||||
`профиля игрока в API Mojang <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_, только вместо
|
||||
идентификации пользователя по UUID используется его ник. Также, как и в API Mojang, вы можете добавить к запросу
|
||||
``?unsigned=false``, чтобы получить текстуры с подписью. В ответе также будет присутствовать дополнительное property
|
||||
с ``name`` равным **ely**.
|
||||
Данный запрос является аналогом запроса `профиля игрока в API Mojang <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape>`_, только вместо идентификации пользователя по UUID используется его ник. Также, как и в API Mojang, вы можете добавить к запросу ``?unsigned=false``, чтобы получить текстуры с подписью. В ответе также будет присутствовать дополнительное property с ``name`` равным **ely**.
|
||||
|
||||
Если у пользователя нет текстур, то они будут запрошены через прокси Mojang, после чего переподписаны с
|
||||
использованием `нашего ключа подписи <#signature-verification-key-request>`_.
|
||||
Если у пользователя нет текстур, то они будут запрошены через прокси Mojang, после чего переподписаны с использованием `нашего ключа подписи <#signature-verification-key-request>`_.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -90,15 +74,12 @@ URL-адреса запросов
|
||||
]
|
||||
}
|
||||
|
||||
Если запрошенный никнейм не будет найден ни в локальном хранилище, ни у Mojang, сервер вернёт пустой ответ с ``204``
|
||||
статусом.
|
||||
Если запрошенный никнейм не будет найден ни в локальном хранилище, ни у Mojang, сервер вернёт пустой ответ с ``204`` статусом.
|
||||
|
||||
.. _signature-verification-key-request:
|
||||
.. function:: /signature-verification-key.der
|
||||
|
||||
Данный запрос возвращает публичный ключ, который может быть использован для проверки подписи текстур. Ключ
|
||||
предоставляется в формате ``DER``. Этот формат используется внутри Authlib, поэтому ключ может быть в ней использован
|
||||
без модификации алгоритма проверки подписи.
|
||||
Данный запрос возвращает публичный ключ, который может быть использован для проверки подписи текстур. Ключ предоставляется в формате ``DER``. Этот формат используется внутри Authlib, поэтому ключ может быть в ней использован без модификации алгоритма проверки подписи.
|
||||
|
||||
.. function:: /signature-verification-key.pem
|
||||
|
||||
@ -106,10 +87,7 @@ URL-адреса запросов
|
||||
|
||||
.. function:: /textures/signed/{nickname}
|
||||
|
||||
Этот запрос используется в нашем `плагине серверной системы скинов <http://ely.by/server-skins-system>`_ для
|
||||
загрузки текстур с оригинальной подписью Mojang. Полученные в ответе текстуры могут быть без изменений переданы в
|
||||
немодифицированный игровой клиент. В ответе также будет присутствовать дополнительное property с :samp:`name`
|
||||
равным **ely**.
|
||||
Этот запрос используется в нашем `плагине серверной системы скинов <https://ely.by/server-skins-system>`_ для загрузки текстур с оригинальной подписью Mojang. Полученные в ответе текстуры могут быть без изменений переданы в немодифицированный игровой клиент. В ответе также будет присутствовать дополнительное property с ``name`` равным **ely**.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -129,23 +107,19 @@ URL-адреса запросов
|
||||
]
|
||||
}
|
||||
|
||||
По умолчанию для этого запроса не применяется проксирование текстур. Чтобы его включить, добавьте дополнительный
|
||||
GET параметр :samp:`?proxy=true`.
|
||||
По умолчанию для этого запроса не применяется проксирование текстур. Чтобы его включить, добавьте дополнительный GET параметр ``?proxy=true``.
|
||||
|
||||
Если текстуры не будут найдены, сервер вернёт пустой ответ с :samp:`204` статусом.
|
||||
Если текстуры не будут найдены, сервер вернёт пустой ответ с ``204`` статусом.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
При совершении любого из вышеописанных запросов вы также можете передать ряд дополнительных GET параметров. Они будут
|
||||
использованы для анализа использования сервиса разными версиями игры.
|
||||
При совершении любого из вышеописанных запросов вы также можете передать ряд дополнительных GET параметров. Они будут использованы для анализа использования сервиса разными версиями игры.
|
||||
|
||||
:version: Версия протокола, по которому идёт запрос на скины. На данный момент это версия :samp:`2` ,
|
||||
т.е. вам необходимо указать :samp:`version=2`.
|
||||
:version: Версия протокола, по которому идёт запрос на скины. На данный момент это версия ``2`` , т.е. вам необходимо указать ``version=2``.
|
||||
|
||||
:minecraft_version: Версия Minecraft, с которой идёт запрос.
|
||||
|
||||
:authlib_version: Версия используемой Authlib. Этот параметр актуален для версий Minecraft 1.7.6+, где
|
||||
для загрузки скинов стала использоваться отдельная библиотека, а не внутриигровой код.
|
||||
:authlib_version: Версия используемой Authlib. Этот параметр актуален для версий Minecraft 1.7.6+, где для загрузки скинов стала использоваться отдельная библиотека, а не внутриигровой код.
|
||||
|
||||
Пример запроса текстур с передачей вышеописанных параметров:
|
||||
|
||||
@ -156,10 +130,7 @@ URL-адреса запросов
|
||||
Вспомогательные URL
|
||||
+++++++++++++++++++
|
||||
|
||||
Также запрос скина и плаща можно выполнить, передавая ник через GET параметр. Эта возможность используется для
|
||||
передачи аналитических параметров в версиях игры до 1.5.2, когда ник просто добавлялся в конец строки. Для этого вся
|
||||
строка выстраивается таким образом, чтобы последним параметром шёл :samp:`name`, после добавления ника к которому
|
||||
получался полный запрос на текстуру.
|
||||
Также запрос скина и плаща можно выполнить, передавая ник через GET параметр. Эта возможность используется для передачи аналитических параметров в версиях игры до 1.5.2, когда ник просто добавлялся в конец строки. Для этого вся строка выстраивается таким образом, чтобы последним параметром шёл ``name``, после добавления ника к которому получался полный запрос на текстуру.
|
||||
|
||||
.. function:: /skins?name={nickname}.png
|
||||
|
||||
@ -181,23 +152,17 @@ URL-адреса запросов
|
||||
Проксирование текстур
|
||||
=====================
|
||||
|
||||
Сервис системы скинов Ely.by получает текстуры из официальной системы скинов в случае, если в базе данных не было
|
||||
найдено информации о текстурах для запрошенного имени пользователя. Также запрос будет проксирован, если запись о скине
|
||||
будет найдена, но он будет стандартным.
|
||||
Сервис системы скинов Ely.by получает текстуры из официальной системы скинов в случае, если в базе данных не было найдено информации о текстурах для запрошенного имени пользователя. Также запрос будет проксирован, если запись о скине будет найдена, но он будет стандартным.
|
||||
|
||||
Для улучшения пропускной способности проксирующего алгоритма, информация о текстурах кешируется в 2 стадии:
|
||||
|
||||
* Соответствие ника и UUID хранится в
|
||||
`течение 30 дней <https://help.minecraft.net/hc/en-us/articles/360034636712-Minecraft-Usernames#article-container:~:text=How%20often%20can%20I%20change%20my%20username%3F>`_.
|
||||
* Соответствие ника и UUID хранится в `течение 30 дней <https://help.minecraft.net/hc/en-us/articles/360034636712-Minecraft-Usernames#article-container:~:text=How%20often%20can%20I%20change%20my%20username%3F>`_.
|
||||
|
||||
* Информация о текстурах обновляется не чаще
|
||||
`раза в минуту <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape:~:text=You%20can%20request%20the%20same%20profile%20once%20per%20minute>`_.
|
||||
* Информация о текстурах обновляется не чаще `раза в минуту <https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape:~:text=You%20can%20request%20the%20same%20profile%20once%20per%20minute>`_.
|
||||
|
||||
Если вы владеете лицензионным аккаунтом Minecraft, но ваш ник занят, пожалуйста, обратитесь в
|
||||
`службу поддержки <http://ely.by/site/contact>`_ и после небольшой проверки мы передадим ник в ваше пользование.
|
||||
Если вы владеете лицензионным аккаунтом Minecraft, но ваш ник занят, пожалуйста, обратитесь в `службу поддержки <https://ely.by/site/contact>`_ и после небольшой проверки мы передадим ник в ваше пользование.
|
||||
|
||||
Готовые реализации
|
||||
==================
|
||||
|
||||
Готовые реализации патчей и инструкции по их установке могут быть найдены в
|
||||
`разделе загрузок на главном сайте Ely.by <http://ely.by/load>`_.
|
||||
Готовые реализации патчей и инструкции по их установке могут быть найдены в `разделе загрузок на главном сайте Ely.by <https://ely.by/load>`_.
|