Skip to content

Commit 9486694

Browse files
authored
Merge pull request #53 from peppy/disallow-duplicate-filenames
Ensure that filenames are globally unique
2 parents 99df39e + baa539c commit 9486694

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

osu.Server.BeatmapSubmission.Tests/BeatmapSubmissionControllerTest.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,37 @@ await db.ExecuteAsync(
10491049
Assert.Contains("Beatmap has invalid ID inside", (await response.Content.ReadFromJsonAsync<ErrorResponse>())!.Error);
10501050
}
10511051

1052+
[Fact]
1053+
public async Task TestUploadFullPackage_FailsIfDuplicateFilename()
1054+
{
1055+
using var db = await DatabaseAccess.GetConnectionAsync();
1056+
await db.ExecuteAsync(
1057+
"INSERT INTO `phpbb_users` (`user_id`, `username`, `username_clean`, `country_acronym`, `user_permissions`, `user_sig`, `user_occ`, `user_interests`) VALUES (1000, 'test', 'test', 'JP', '', '', '', '')");
1058+
1059+
await db.ExecuteAsync(
1060+
@"INSERT INTO `osu_beatmapsets` (`beatmapset_id`, `user_id`, `creator`, `approved`, `thread_id`, `active`, `submit_date`) VALUES (241526, 1000, 'test user', -1, 0, -1, CURRENT_TIMESTAMP)");
1061+
1062+
foreach (uint beatmapId in new uint[] { 557815, 557814, 557821, 557816, 557817, 557818, 557812, 557810, 557811, 557820, 557813, 557819 })
1063+
await db.ExecuteAsync(@"INSERT INTO `osu_beatmaps` (`beatmap_id`, `user_id`, `beatmapset_id`, `approved`) VALUES (@beatmapId, 1000, 241526, -1)", new { beatmapId = beatmapId });
1064+
1065+
// A different beatmap exists with a filename from the upload.
1066+
// Filenames should be unique globally.
1067+
await db.ExecuteAsync(@"INSERT INTO `osu_beatmaps` (`beatmap_id`, `filename`) VALUES (@beatmapId, @filename)", new { beatmapId = 123456, filename = "Soleily - Renatus (test) [Platter].osu" });
1068+
1069+
var request = new HttpRequestMessage(HttpMethod.Put, "/beatmapsets/241526");
1070+
1071+
using var content = new MultipartFormDataContent($"{Guid.NewGuid()}----");
1072+
using var stream = TestResources.GetResource(osz_filename)!;
1073+
content.Add(new StreamContent(stream), "beatmapArchive", osz_filename);
1074+
request.Content = content;
1075+
request.Headers.Add(HeaderBasedAuthenticationHandler.USER_ID_HEADER, "1000");
1076+
1077+
var response = await Client.SendAsync(request);
1078+
Assert.False(response.IsSuccessStatusCode);
1079+
Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode);
1080+
Assert.Contains("Filename already exists as part of different beatmap set", (await response.Content.ReadFromJsonAsync<ErrorResponse>())!.Error);
1081+
}
1082+
10521083
[Theory]
10531084
[InlineData("../suspicious")]
10541085
[InlineData("..\\suspicious")]

osu.Server.BeatmapSubmission/BeatmapSubmissionController.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,12 @@ private async Task<bool> updateBeatmapSetFromArchiveAsync(osu_beatmapset beatmap
438438

439439
if (packageFile.BeatmapContent is BeatmapContent content)
440440
{
441-
if (!beatmapIds.Remove((uint)content.Beatmap.BeatmapInfo.OnlineID))
441+
uint beatmapId = (uint)content.Beatmap.BeatmapInfo.OnlineID;
442+
443+
if (await db.FilenameExistsForDifferentBeatmapAsync(beatmapId, packageFile.VersionFile.filename, transaction))
444+
throw new InvariantException($"Filename already exists as part of different beatmap set ({packageFile.VersionFile.filename})", LogLevel.Warning);
445+
446+
if (!beatmapIds.Remove(beatmapId))
442447
throw new InvariantException($"Beatmap has invalid ID inside ({packageFile.VersionFile.filename}).", LogLevel.Warning);
443448

444449
await db.UpdateBeatmapAsync(content.GetDatabaseRow(), transaction);
@@ -456,7 +461,10 @@ private async Task<bool> updateBeatmapSetFromArchiveAsync(osu_beatmapset beatmap
456461
await beatmapStorage.StoreBeatmapSetAsync(beatmapSet.beatmapset_id, await beatmapStream.ReadAllBytesToArrayAsync(), parseResult);
457462

458463
if (await db.IsBeatmapSetNominatedAsync(beatmapSet.beatmapset_id))
459-
await sharedInterop.DisqualifyBeatmapSetAsync(beatmapSet.beatmapset_id, "This beatmap set was updated by the mapper after a nomination. Please ensure to re-check the beatmaps for new issues. If you are the mapper, please comment in this thread on what you changed.");
464+
{
465+
await sharedInterop.DisqualifyBeatmapSetAsync(beatmapSet.beatmapset_id,
466+
"This beatmap set was updated by the mapper after a nomination. Please ensure to re-check the beatmaps for new issues. If you are the mapper, please comment in this thread on what you changed.");
467+
}
460468

461469
await mirrorService.PurgeBeatmapSetAsync(db, beatmapSet.beatmapset_id);
462470

osu.Server.BeatmapSubmission/DatabaseOperationExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,18 @@ public static Task InsertBeatmapsetVersionFileAsync(this MySqlConnection db, bea
394394
transaction);
395395
}
396396

397+
public static async Task<bool> FilenameExistsForDifferentBeatmapAsync(this MySqlConnection db, uint beatmapId, string filename, MySqlTransaction? transaction = null)
398+
{
399+
return await db.QuerySingleAsync<uint>(
400+
"SELECT COUNT(1) FROM osu_beatmaps WHERE filename = @filename AND beatmap_id != @beatmap_id AND deleted_at IS NULL",
401+
new
402+
{
403+
beatmap_id = beatmapId,
404+
filename = filename,
405+
},
406+
transaction) > 0;
407+
}
408+
397409
public static async Task<bool> IsBeatmapSetInProcessingQueueAsync(this MySqlConnection db, uint beatmapSetId, MySqlTransaction? transaction = null)
398410
{
399411
return await db.QuerySingleAsync<uint>(

0 commit comments

Comments
 (0)