mirror of
				https://github.com/elyby/chrly.git
				synced 2025-05-31 14:11:51 +05:30 
			
		
		
		
	Rename the signature key param.
Rename the signature verification key endpoint. Update CHANGELOG and README files
This commit is contained in:
		| @@ -6,8 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||
|  | ||||
| ## [Unreleased] - xxxx-xx-xx | ||||
| ### Added | ||||
| - `/profile/{username}` endpoint. | ||||
| - `/signing-key` endpoint. | ||||
| - `/profile/{username}` endpoint, which returns a profile and its textures, equivalent of the Mojang's | ||||
|   [UUID -> Profile + Skin/Cape endpoint](https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape). | ||||
| - `/signature-verification-key` endpoint, which returns the public key in `DER` format for signature verification. | ||||
|  | ||||
| ### Fixed | ||||
| - [#29](https://github.com/elyby/chrly/issues/29) If a previously cached UUID no longer exists, | ||||
| @@ -15,7 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||
| - Use correct status code for error about empty response from Mojang's API. | ||||
|  | ||||
| ### Changed | ||||
| - All skinsystem's endpoints are now returns `500` status code when an error occurred during request processing. | ||||
| - **BREAKING**: `/cloaks/{username}` and `/textures/{username}` endpoints will no longer return a cape if there are no | ||||
|   textures for the requested username. | ||||
| - All endpoints are now returns `500` status code when an error occurred during request processing. | ||||
|  | ||||
| ## [4.5.0] - 2020-05-01 | ||||
| ### Added | ||||
|   | ||||
							
								
								
									
										84
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								README.md
									
									
									
									
									
								
							| @@ -15,8 +15,9 @@ production ready. | ||||
| ## Installation | ||||
|  | ||||
| You can easily install Chrly using [docker-compose](https://docs.docker.com/compose/). The configuration below (save | ||||
| it as `docker-compose.yml`) can be used to start a Chrly server. It relies on `CHRLY_SECRET` environment variable | ||||
| that you must set before running `docker-compose up -d`. Other possible variables are described below. | ||||
| it as `docker-compose.yml`) can be used to start a Chrly server. It relies on `CHRLY_SECRET` and `CHRLY_SIGNING_KEY` | ||||
| environment variables that you must set before running `docker-compose up -d`. Other possible variables are described | ||||
| below. | ||||
|  | ||||
| ```yml | ||||
| version: '2' | ||||
| @@ -33,6 +34,7 @@ services: | ||||
|       - "80:80" | ||||
|     environment: | ||||
|       CHRLY_SECRET: replace_this_value_in_production | ||||
|       CHRLY_SIGNING_KEY: base64:LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCT3dJQkFBSkJBTmJVcFZDWmtNS3BmdllaMDhXM2x1bWRBYVl4TEJubVVEbHpIQlFIM0RwWWVmNVdDTzMyClREVTZmZUlKNThBMGxBeXdndFo0d3dpMmRHSE96LzFoQXZjQ0F3RUFBUUpBSXRheFNIVGU2UEtieUVVLzlweGoKT05kaFlSWXdWTExvNTZnbk1ZaGt5b0VxYWFNc2ZvdjhoaG9lcGtZWkJNdlpGQjJiRE9zUTJTYUorRTJlaUJPNApBUUloQVBzc1MwK0JSOXcwYk9kbWpHcW1kRTlOck41VUpRY09XMTNzMjkrNlF6VUJBaUVBMnZXT2VwQTVBcGl1CnBFQTNwd29HZGtWQ3JOU25uS2pEUXpEWEJucGQzL2NDSUVGTmQ5c1k0cVVHNEZXZFhONlJubVhMN1NqMHVaZkgKRE13enU4ckVNNXNCQWlFQWh2ZG9ETnFMbWJNZHEzYytGc1BTT2VMMWQyMVpwL0pLOGtiUHRGbUhOZjhDSVFEVgo2RlNaRHd2V2Z1eGFNN0JzeWNRT05rakRCVFBOdStscWN0SkJHbkJ2M0E9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= | ||||
|  | ||||
|   redis: | ||||
|     image: redis:4.0-32bit | ||||
| @@ -41,6 +43,11 @@ services: | ||||
|       - ./data/redis:/data | ||||
| ``` | ||||
|  | ||||
| **Tip**: to generate a value for the `CHRLY_SIGNING_KEY` use the command below and then join it with a `base64:` prefix. | ||||
| ```sh | ||||
| openssl genrsa 4096 | base64 -w0 | ||||
| ``` | ||||
|  | ||||
| Chrly uses some volumes to persist storage for capes and Redis database. The configuration above mounts them to | ||||
| the host machine to do not lose data on container recreations. | ||||
|  | ||||
| @@ -48,11 +55,10 @@ the host machine to do not lose data on container recreations. | ||||
|  | ||||
| Application's configuration is based on the environment variables. You can adjust config by modifying `environment` key | ||||
| inside your `docker-compose.yml` file. After value will have been changed, container should be stopped and recreated. | ||||
| If environment variables have been changed, Docker will automatically recreate the container, so you only need to `stop` | ||||
| and `up` it: | ||||
| If environment variables have been changed, Docker will automatically recreate the container, so you only need to `up` | ||||
| it again: | ||||
|  | ||||
| ```sh | ||||
| docker-compose stop app | ||||
| docker-compose up -d app | ||||
| ``` | ||||
|  | ||||
| @@ -182,7 +188,7 @@ If something goes wrong, you can always access logs by executing `docker-compose | ||||
|  | ||||
| ## Endpoints | ||||
|  | ||||
| Each endpoint that accepts `username` as a part of an url takes it case insensitive. `.png` part can be omitted too. | ||||
| Each endpoint that accepts `username` as a part of an url takes it case-insensitive. The `.png` postfix can be omitted. | ||||
|  | ||||
| #### `GET /skins/{username}.png` | ||||
|  | ||||
| @@ -220,11 +226,71 @@ That request is handy in case when your server implements authentication for a g | ||||
| operation) and you have to respond with hasJoined request with an actual user textures. You have to simply send request | ||||
| to the Chrly server and put the result in your hasJoined response. | ||||
|  | ||||
| #### `GET /profile/{username}` | ||||
|  | ||||
| This endpoint behaves exactly like the | ||||
| [Mojang's UUID -> Profile + Skin/Cape endpoint](https://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape), but using | ||||
| a username instead of the UUID. Just like in the Mojang's API, you can append `?unsigned=false` part to URL to sign | ||||
| the `textures` property. If the textures for the requested username aren't found, it'll request them through the | ||||
| Mojang's API, but the Mojang's signature will be discarded and the textures will be re-signed using the signature key | ||||
| for your Chrly instance. | ||||
|  | ||||
| Response example: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|     "id": "0f657aa8bfbe415db7005750090d3af3", | ||||
|     "name": "username", | ||||
|     "properties": [ | ||||
|         { | ||||
|             "name": "textures", | ||||
|             "signature": "signature value", | ||||
|             "value": "base64 encoded value" | ||||
|         }, | ||||
|         { | ||||
|             "name": "chrly", | ||||
|             "value": "how do you tame a horse in Minecraft?" | ||||
|         } | ||||
|     ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| The base64 `value` string for the `textures` property decoded: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|     "timestamp": 1614387238630, | ||||
|     "profileId": "0f657aa8bfbe415db7005750090d3af3", | ||||
|     "profileName": "username", | ||||
|     "textures": { | ||||
|         "SKIN": { | ||||
|             "url": "http://example.com/skin.png" | ||||
|         }, | ||||
|         "CAPE": { | ||||
|             "url": "http://example.com/cape.png" | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| If username can't be found locally and can't be obtained from the Mojang's API, empty response with `204` status code | ||||
| will be sent. | ||||
|  | ||||
| Note that this endpoint will try to use the UUID for the stored profile in the database. This is an edge case, related | ||||
| to the situation where the user is available in the database but has no textures, which caused them to be retrieved | ||||
| from the Mojang's API. | ||||
|  | ||||
| #### `GET /signature-verification-key` | ||||
|  | ||||
| This endpoint returns a public key that can be used to verify textures signatures. The key is provided in `DER` format, | ||||
| so it can be used directly in the Authlib, without modifying the signature checking algorithm. | ||||
|  | ||||
| #### `GET /textures/signed/{username}` | ||||
|  | ||||
| Actually, it's [Ely.by](http://ely.by) feature called [Server Skins System](http://ely.by/server-skins-system), but if | ||||
| you have your own source of Mojang's signatures, then you can pass it with textures and it'll be displayed in response | ||||
| of this endpoint. Received response should be directly sent to the client without any modification via game server API. | ||||
| Actually, this is the [Ely.by](https://ely.by)'s feature called | ||||
| [Server Skins System](https://ely.by/server-skins-system), but if you have your own source of Mojang's signatures, | ||||
| then you can pass it with textures and it'll be displayed in response of this endpoint. Received response should be | ||||
| directly sent to the client without any modification via game server API. | ||||
|  | ||||
| Response example: | ||||
|  | ||||
|   | ||||
| @@ -20,11 +20,9 @@ var signer = di.Options( | ||||
| ) | ||||
|  | ||||
| func newTexturesSigner(config *viper.Viper) (*Signer, error) { | ||||
| 	// TODO: add CHANGELOG and README entries about this variable | ||||
| 	// TODO: rename param variable | ||||
| 	keyStr := config.GetString("textures.signer.pem") | ||||
| 	keyStr := config.GetString("chrly.signing.key") | ||||
| 	if keyStr == "" { | ||||
| 		return nil, errors.New("texturesSigner.pem must be set in order to sign textures") | ||||
| 		return nil, errors.New("chrly.signing.key must be set in order to sign textures") | ||||
| 	} | ||||
|  | ||||
| 	var keyBytes []byte | ||||
|   | ||||
| @@ -71,7 +71,7 @@ func (ctx *Skinsystem) Handler() *mux.Router { | ||||
| 	router.HandleFunc("/skins", ctx.skinGetHandler).Methods(http.MethodGet) | ||||
| 	router.HandleFunc("/cloaks", ctx.capeGetHandler).Methods(http.MethodGet) | ||||
| 	// Utils | ||||
| 	router.HandleFunc("/signing-key", ctx.signingKeyHandler).Methods(http.MethodGet) | ||||
| 	router.HandleFunc("/signature-verification-key", ctx.signatureVerificationKeyHandler).Methods(http.MethodGet) | ||||
|  | ||||
| 	return router | ||||
| } | ||||
| @@ -102,7 +102,6 @@ func (ctx *Skinsystem) skinGetHandler(response http.ResponseWriter, request *htt | ||||
| 	ctx.skinHandler(response, request) | ||||
| } | ||||
|  | ||||
| // TODO: write CHANGELOG about breaking change in this method | ||||
| func (ctx *Skinsystem) capeHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	profile, err := ctx.getProfile(request, true) | ||||
| 	if err != nil { | ||||
| @@ -182,7 +181,6 @@ func (ctx *Skinsystem) signedTexturesHandler(response http.ResponseWriter, reque | ||||
| 	_, _ = response.Write(responseJson) | ||||
| } | ||||
|  | ||||
| // TODO: add README entry about this method | ||||
| func (ctx *Skinsystem) profileHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	profile, err := ctx.getProfile(request, true) | ||||
| 	if err != nil { | ||||
| @@ -235,8 +233,7 @@ func (ctx *Skinsystem) profileHandler(response http.ResponseWriter, request *htt | ||||
| 	_, _ = response.Write(responseJson) | ||||
| } | ||||
|  | ||||
| // TODO: add README entry about this method | ||||
| func (ctx *Skinsystem) signingKeyHandler(response http.ResponseWriter, request *http.Request) { | ||||
| func (ctx *Skinsystem) signatureVerificationKeyHandler(response http.ResponseWriter, request *http.Request) { | ||||
| 	publicKey, err := ctx.TexturesSigner.GetPublicKey() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
|   | ||||
| @@ -1108,12 +1108,12 @@ var signingKeyTestsCases = []*skinsystemTestCase{ | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func (suite *skinsystemTestSuite) TestSigningKey() { | ||||
| func (suite *skinsystemTestSuite) TestSignatureVerificationKey() { | ||||
| 	for _, testCase := range signingKeyTestsCases { | ||||
| 		suite.RunSubTest(testCase.Name, func() { | ||||
| 			testCase.BeforeTest(suite) | ||||
|  | ||||
| 			req := httptest.NewRequest("GET", "http://chrly/signing-key", nil) | ||||
| 			req := httptest.NewRequest("GET", "http://chrly/signature-verification-key", nil) | ||||
| 			w := httptest.NewRecorder() | ||||
|  | ||||
| 			if testCase.PanicErr != "" { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user