Skip to content

Commit 1f27993

Browse files
committed
Mobile api testing
1 parent a303a03 commit 1f27993

File tree

3 files changed

+162
-148
lines changed

3 files changed

+162
-148
lines changed

Roblox/Roblox.Website/Controllers/Internal/BypassController.cs

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -48,108 +48,7 @@ namespace Roblox.Website.Controllers
4848
[MVC.ApiController]
4949
[MVC.Route("/")]
5050
public class BypassController : ControllerBase
51-
{
52-
[HttpGetBypass("/mobileapi/check-app-version")]
53-
[HttpPostBypass("/mobileapi/check-app-version")]
54-
public MVC.IActionResult MobileCheckAppVer()
55-
{
56-
return Ok(new
57-
{
58-
data = new
59-
{
60-
UpgradeAction = "None"
61-
}
62-
});
63-
}
64-
[HttpGetBypass("/device/initialize")]
65-
[HttpPostBypass("/device/initialize")]
66-
public MVC.IActionResult InitDevice()
67-
{
68-
return Ok(new
69-
{
70-
browserTrackerId = 1234567890,
71-
appDeviceIdentifier = (string?)null,
72-
});
73-
}
74-
[HttpGetBypass("v2/get-rollout-settings")]
75-
public dynamic ChatRollout(string featureNames)
76-
{
77-
return new
78-
{
79-
rolloutFeatures = new[]
80-
{
81-
new
82-
{
83-
featureName = featureNames,
84-
isRolloutEnabled = true
85-
}
86-
}
87-
};
88-
}
89-
[HttpGetBypass("sponsoredpage/list-json")]
90-
[HttpGetBypass("mobile-ads/v1/get-ad-details")]
91-
[HttpGetBypass("incoming-items/counts")]
92-
public dynamic IncomingItems()
93-
{
94-
return new
95-
{
96-
success = true
97-
};
98-
}
99-
100-
[HttpPostBypass("v1/logout")]
101-
[HttpGetBypass("sign-out/v1")]
102-
[HttpPostBypass("sign-out/v1")]
103-
[HttpGetBypass("game/logout.aspx")]
104-
public void Logoutv1w()
105-
{
106-
using var sessCache = Roblox.Services.ServiceProvider.GetOrCreate<UserSessionsCache>();
107-
sessCache.Remove(safeUserSession.sessionId);
108-
HttpContext.Response.Cookies.Delete(Middleware.SessionMiddleware.CookieName);
109-
}
110-
[HttpGetBypass("client/pbe")]
111-
[HttpPostBypass("client/pbe")]
112-
[HttpGetBypass("mobile/pbe")]
113-
public MVC.IActionResult PBE()
114-
{
115-
return Ok();
116-
}
117-
118-
[HttpGetBypass("v1/enrollments")]
119-
[HttpPostBypass("v1/enrollments")]
120-
public dynamic Enrollments()
121-
{
122-
return new
123-
{
124-
data = new[]
125-
{
126-
new
127-
{
128-
SubjectType = "BrowserTracker",
129-
SubjectTargetId = 63713166375,
130-
ExperimentName = "AllUsers.DevelopSplashScreen.GreenStartCreatingButton",
131-
Status = "Inactive",
132-
Variation = (string?)null
133-
}
134-
}
135-
};
136-
}
137-
138-
[HttpGetBypass("v1/get-enrollments")]
139-
[HttpPostBypass("v1/get-enrollments")]
140-
public dynamic GetEnrollments()
141-
{
142-
return Array.Empty<object>();
143-
}
144-
145-
// implemented cuz client likes to spam this so this might improve network performance?
146-
[HttpGetBypass("pe")]
147-
[HttpPostBypass("pe")]
148-
public dynamic GetPe()
149-
{
150-
return Array.Empty<object>();
151-
}
152-
51+
{
15352
[HttpGet("logout")]
15453
public MVC.IActionResult Logout()
15554
{
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Net.Http;
6+
using System.Net.Http.Json;
7+
using System.Security.Cryptography;
8+
using System.Text;
9+
using System.Text.Json;
10+
using System.Threading.Tasks;
11+
using System.Net;
12+
using Microsoft.AspNetCore.Http;
13+
using Microsoft.AspNetCore.Mvc;
14+
using Newtonsoft.Json;
15+
using Roblox.Exceptions;
16+
using Roblox.Logging;
17+
using Roblox.Models.Users;
18+
using Roblox.Services;
19+
using Roblox.Services.App.FeatureFlags;
20+
using Roblox.Website.Middleware;
21+
using BadRequestException = Roblox.Exceptions.BadRequestException;
22+
using MVC = Microsoft.AspNetCore.Mvc;
23+
using Roblox.Services.Exceptions;
24+
using Roblox.Website.WebsiteModels.Discord;
25+
using Npgsql;
26+
using Dapper;
27+
using Roblox.Dto.Users;
28+
29+
30+
namespace Roblox.Website.Controllers
31+
{
32+
[MVC.ApiController]
33+
[MVC.Route("/")]
34+
public class MobileShitTesting : ControllerBase
35+
{
36+
[HttpGetBypass("/mobileapi/check-app-version")]
37+
[HttpPostBypass("/mobileapi/check-app-version")]
38+
public MVC.IActionResult MobileCheckAppVer()
39+
{
40+
return Ok(new
41+
{
42+
data = new
43+
{
44+
UpgradeAction = "None"
45+
}
46+
});
47+
}
48+
49+
[HttpGetBypass("/device/initialize")]
50+
[HttpPostBypass("/device/initialize")]
51+
public MVC.IActionResult InitDevice()
52+
{
53+
return Ok(new
54+
{
55+
browserTrackerId = 1,
56+
appDeviceIdentifier = (string?)null,
57+
});
58+
}
59+
60+
private async Task RateLimitCheck()
61+
{
62+
var loginKey = "LoginAttemptCountV1:" + GetIP();
63+
var attemptCount = (await services.cooldown.GetBucketDataForKey(loginKey, TimeSpan.FromMinutes(10))).ToArray();
64+
65+
if (!await services.cooldown.TryIncrementBucketCooldown(loginKey, 15, TimeSpan.FromMinutes(10), attemptCount, true))
66+
{
67+
throw new ForbiddenException(15, "Too many attempts, please wait about 10 minutes before retrying!");
68+
}
69+
}
70+
71+
public class MobileLoginReq
72+
{
73+
public string username { get; set; }
74+
public string password { get; set; }
75+
}
76+
77+
[HttpPostBypass("mobileapi/login")]
78+
public async Task<dynamic> MobileLogin([FromBody] MobileLoginReq request)
79+
{
80+
FeatureFlags.FeatureCheck(FeatureFlag.LoginEnabled);
81+
await RateLimitCheck();
82+
83+
if (string.IsNullOrEmpty(request.username) || string.IsNullOrEmpty(request.password))
84+
throw new BadRequestException(3, "Username and Password are required. Please try again.");
85+
86+
UserInfo userInfo;
87+
try
88+
{
89+
userInfo = await services.users.GetUserByName(request.username);
90+
}
91+
catch (RecordNotFoundException)
92+
{
93+
throw new ForbiddenException(1, "Incorrect username or password. Please try again.");
94+
}
95+
96+
if(await Login(request.username, request.password, userInfo.userId))
97+
await CreateSessionAndSetCookie(userInfo.userId);
98+
99+
var userBalance = await services.economy.GetUserBalance(userInfo.userId);
100+
101+
return new
102+
{
103+
Status = "OK",
104+
UserInfo = new
105+
{
106+
UserName = request.username,
107+
RobuxBalance = userBalance.robux,
108+
TicketsBalance = userBalance.tickets,
109+
IsAnyBuildersClubMember = true,
110+
ThumbnailUrl = $"{Configuration.BaseUrl}/Thumbs/Avatar.ashx?userId={userInfo.userId}",
111+
UserID = userInfo.userId
112+
}
113+
};
114+
}
115+
116+
private async Task<bool> Login(string username, string password, long userId)
117+
{
118+
try
119+
{
120+
FeatureFlags.FeatureCheck(FeatureFlag.LoginEnabled);
121+
}
122+
catch (RobloxException)
123+
{
124+
throw new RobloxException(503, 0, "Login is currently disabled. Please try again later.");
125+
}
126+
await RateLimitCheck();
127+
try
128+
{
129+
if (!await services.users.VerifyPassword(userId, password))
130+
throw new ForbiddenException(1, "Incorrect username or password. Please try again");
131+
}
132+
catch (RecordNotFoundException)
133+
{
134+
throw new ForbiddenException(4, "Your account has been locked. Please reset your password to unlock your account.");
135+
}
136+
137+
return true;
138+
}
139+
140+
private async Task<string> CreateSessionAndSetCookie(long userId)
141+
{
142+
var sessionCookie = Middleware.SessionMiddleware.CreateJwt(new Middleware.JwtEntry()
143+
{
144+
sessionId = await services.users.CreateSession(userId),
145+
createdAt = DateTimeOffset.Now.ToUnixTimeSeconds(),
146+
});
147+
148+
HttpContext.Response.Cookies.Append(Middleware.SessionMiddleware.CookieName, sessionCookie, new CookieOptions()
149+
{
150+
Domain = ".{Configuration.BaseUrl}",
151+
Secure = false,
152+
Expires = DateTimeOffset.Now.Add(TimeSpan.FromDays(364)),
153+
IsEssential = true,
154+
Path = "/",
155+
SameSite = SameSiteMode.Lax,
156+
});
157+
return sessionCookie;
158+
}
159+
}
160+
}

Roblox/Roblox.Website/Controllers/Internal/Other/Studio.cs

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ private async Task RateLimitCheck()
3939

4040
if (!await services.cooldown.TryIncrementBucketCooldown(loginKey, 15, TimeSpan.FromMinutes(10), attemptCount, true))
4141
{
42-
throw new ForbiddenException(15, "Too many attempts please wait 10 minutes before trying again.");
42+
throw new ForbiddenException(15, "Too many attempts, please wait about 10 minutes before retrying!");
4343
}
4444
}
4545

@@ -157,51 +157,6 @@ public async Task<dynamic> LoginV2()
157157
};
158158
}
159159

160-
public class MobileLoginReq
161-
{
162-
public string username { get; set; }
163-
public string password { get; set; }
164-
}
165-
166-
[HttpPostBypass("mobileapi/login")]
167-
public async Task<dynamic> MobileLogin([FromBody] MobileLoginReq request)
168-
{
169-
FeatureFlags.FeatureCheck(FeatureFlag.LoginEnabled);
170-
await RateLimitCheck();
171-
172-
if (string.IsNullOrEmpty(request.username) || string.IsNullOrEmpty(request.password))
173-
throw new BadRequestException(3, "Username and Password are required. Please try again.");
174-
175-
UserInfo userInfo;
176-
try
177-
{
178-
userInfo = await services.users.GetUserByName(request.username);
179-
}
180-
catch (RecordNotFoundException)
181-
{
182-
throw new ForbiddenException(1, "Incorrect username or password. Please try again.");
183-
}
184-
185-
if(await Login(request.username, request.password, userInfo.userId))
186-
await CreateSessionAndSetCookie(userInfo.userId);
187-
188-
var userBalance = await services.economy.GetUserBalance(userInfo.userId);
189-
190-
return new
191-
{
192-
Status = "OK",
193-
UserInfo = new
194-
{
195-
UserName = request.username,
196-
RobuxBalance = userBalance.robux,
197-
TicketsBalance = userBalance.tickets,
198-
IsAnyBuildersClubMember = true,
199-
ThumbnailUrl = $"{Configuration.BaseUrl}/Thumbs/Avatar.ashx?userId={userInfo.userId}",
200-
UserID = userInfo.userId
201-
}
202-
};
203-
}
204-
205160
private async Task<bool> Login(string username, string password, long userId)
206161
{
207162
try

0 commit comments

Comments
 (0)