Skip to content

Commit b11737f

Browse files
authored
Add support for per-request signed profile requests (#182)
I've revised the logic for requesting signed profiles and aligned them to what Mojang does in the vanilla server jar. Signed profiles should be explicitly requested and should skip the cache (as this needs the most recent, signed information). Unsigned profiles can be cached indefinitely. I've also removed the setting, always defaulting to unsigned, as there's no benefit in always requesting signed profiles.
1 parent f91c387 commit b11737f

6 files changed

Lines changed: 33 additions & 15 deletions

File tree

config/default.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# See config documantation at src/config.rs.
22

3-
signed_profiles = false
4-
53
[cache.entries]
64
uuid = { exp = "PT120M", exp_empty = "PT5M" }
75
profile = { exp = "PT10M", exp_empty = "PT5M" }

proto/profile.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ message UuidsResponse {
5757
message ProfileRequest {
5858
// The UUID in simple or hyphenated form whose Minecraft Profile should be queried.
5959
string uuid = 1;
60+
// Whether the response should omit the Yggdrasil signatures on profile properties. Defaults to true (unsigned).
61+
// Signed requests are always fetched live and are not served from cache.
62+
optional bool unsigned = 2;
6063
}
6164

6265
// ProfileProperty is a single property of a Minecraft Profile, that is possibly signed.

src/config.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,6 @@ pub struct Sentry {
229229
/// with status ok.
230230
#[derive(Debug, Clone, Deserialize)]
231231
pub struct Config {
232-
/// Whether the profiles should be requested with a signature.
233-
pub signed_profiles: bool,
234232
/// The service cache configuration.
235233
pub cache: Cache,
236234

src/grpc_services.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ where
8787
handler: "grpc",
8888
})
8989
.inc();
90-
let uuid = Uuid::try_parse(&request.into_inner().uuid).map_err(UuidError)?;
91-
let profile = self.service.get_profile(&uuid).await?;
90+
let inner = request.into_inner();
91+
let uuid = Uuid::try_parse(&inner.uuid).map_err(UuidError)?;
92+
let unsigned = inner.unsigned.unwrap_or(true);
93+
let profile = self.service.get_profile(&uuid, unsigned).await?;
9294
Ok(Response::new(profile.into()))
9395
}
9496

src/rest_services.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ where
128128
})
129129
.inc();
130130
let uuid = Uuid::try_parse(&payload.uuid)?;
131-
Ok(Json(service.get_profile(&uuid).await?.into()))
131+
let unsigned = payload.unsigned.unwrap_or(true);
132+
Ok(Json(service.get_profile(&uuid, unsigned).await?.into()))
132133
}
133134

134135
/// An [axum] handler for [SkinRequest] rest gateway.

src/service.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,29 @@ where
217217
}
218218

219219
/// Gets the profile for an uuid from cache or mojang.
220+
///
221+
/// If `unsigned` is `false`, the request is always fetched live from Mojang so that the Yggdrasil
222+
/// signatures are included and guaranteed to be fresh. The result is also written to cache so that
223+
/// subsequent unsigned requests benefit from it.
220224
#[tracing::instrument(skip(self))]
221225
#[metrics::metrics(metric = "service", labels(request_type = "profile"), handler = metrics_age_handler)]
222-
pub async fn get_profile(&self, uuid: &Uuid) -> Result<Dated<ProfileData>, ServiceError> {
226+
pub async fn get_profile(
227+
&self,
228+
uuid: &Uuid,
229+
unsigned: bool,
230+
) -> Result<Dated<ProfileData>, ServiceError> {
231+
// signed requests are always fetched live; result is also written to cache for unsigned consumers
232+
if !unsigned {
233+
return match self.mojang.fetch_profile(uuid, true).await {
234+
Ok(profile) => {
235+
self.cache.set_profile(uuid, Some(profile.clone())).await;
236+
Ok(Dated::from(profile))
237+
}
238+
Err(ApiError::NotFound) => Err(NotFound),
239+
Err(ApiError::Unavailable) => Err(Unavailable),
240+
};
241+
}
242+
223243
// try to get from the cache
224244
let cached = self.cache.get_profile(uuid).await;
225245
let fallback = match cached {
@@ -229,11 +249,7 @@ where
229249
};
230250

231251
// try to fetch from mojang and update the cache
232-
match self
233-
.mojang
234-
.fetch_profile(uuid, self.config.signed_profiles)
235-
.await
236-
{
252+
match self.mojang.fetch_profile(uuid, false).await {
237253
Ok(profile) => {
238254
let dated = self.cache.set_profile(uuid, Some(profile)).await.unwrap();
239255
Ok(dated)
@@ -261,7 +277,7 @@ where
261277
};
262278

263279
// try to get a profile
264-
let profile = match self.get_profile(uuid).await {
280+
let profile = match self.get_profile(uuid, true).await {
265281
Ok(profile) => profile.data,
266282
Err(Unavailable) => {
267283
return fallback
@@ -316,7 +332,7 @@ where
316332
};
317333

318334
// try to get the profile
319-
let profile = match self.get_profile(uuid).await {
335+
let profile = match self.get_profile(uuid, true).await {
320336
Ok(profile) => profile.data,
321337
Err(Unavailable) => {
322338
return fallback

0 commit comments

Comments
 (0)