mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
6ee1d6f9b3
Every change below was checked against the 2023-03-21 client disassembly;
file:line evidence is in the code comments and in
docs/recroom-2023-client-api-complete.md.
Presence
- matchmake/none means "online, in no room" (its only caller is
TryGoToOfflineRoom, which ignores the reply). The server used to keep the
old room or invent a dorm, so the next heartbeat looked out of sync and
the client cancelled its load to chase that room.
- The join watchdog no longer clears presence 30 s into a long room load;
it is a 3 minute backstop that drops the room only.
- One fan-out (PresenceBroadcastService) for every transition: deferred
joins, matchmake/none, logout, failed joins, visibility changes, SignalR
connect/disconnect. isOnline is sent on its own; pushes never go to the
subject, because a self push moves the player.
- Online-status visibility (Public / Friends / Favorites / Appear offline)
is stored and honoured by GET /player and by the live pushes.
Profile
- PUT account/me/{emoji,personalpronouns,identityflags,bannerimage} were
404; added with the client's real form keys and persisted (new Players
columns plus migration). Every account read now returns them, and edits
push AccountUpdate to everyone.
Outfit menu
- Saved outfits kept OutfitSelectionsV2 and CustomAvatarItems, so loading a
slot restores what was saved instead of a stale outfit.
- isCreationAllowedForAccount answers the {Success, Error} envelope the
client parses; minPriceForPublicItem is a bare int; gifts/generate accepts
form bodies; lockeditems returns the full owned-item shape; colourways no
longer share their base item's AvatarItemId.
RecNetResult writes
- About 40 writes look status-only but parse the body as {Success, Error}.
An empty 200 showed "Failed to ..." after the server applied the change,
and a body without Success threw "Error message cannot be null". Clubs,
announcements, keepsakes, comments/read, subscriptions, purchase offers
and privacy settings now answer RecNetResult.
- Login token and device-code grants are real; remoteauth approves the
device code; createlogintoken returns a bare string.
- New: incentivizedreferrals/referrals, account/bulk/{email,phone},
GET strings, account/me/confirmphone, PlayMenuCarouselOrdering_1.
Route inventory and coverage test extended to match.
README now describes the 2023 branch.
167 lines
6.4 KiB
C#
167 lines
6.4 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace DorkNet.Models.Auth;
|
|
|
|
// =====================================================================
|
|
// JSON keys verified by disassembling each .Deserialize method body
|
|
// directly from GameAssembly.dll. Each key here is the literal string
|
|
// passed to Util.GetKey / Util.GetKeyOrDefault inside the client. Util.GetKey
|
|
// uses Dictionary<string,object>.TryGetValue, which is case-sensitive — so
|
|
// the keys MUST match exactly.
|
|
//
|
|
// Convention summary (it's mixed):
|
|
// RecNetResult lowercase "success", "error"
|
|
// Account camelCase "accountId", "displayName", "isJunior"…
|
|
// SelfAccount camelCase "email", "birthday", "juniorState"…
|
|
// LoginResponse snake_case (OAuth) "access_token", "error_description"…
|
|
// RefreshLoginResp. lowercase "token"
|
|
// CachedLogin camelCase "platformId", "lastLoginTime"…
|
|
// CreateAccountResp uses "value" as the wrapper key for the Account dict
|
|
//
|
|
// NOTE: TreatAsJunior on the C# side maps to JSON key "isJunior" — they
|
|
// don't match. Account.Deserialize reads dict["isJunior"], not dict["treatAsJunior"].
|
|
// =====================================================================
|
|
|
|
/// <summary>
|
|
/// RecNet.RecNetResult — dump.cs:584325, Deserialize at RVA 0x1146340.
|
|
/// Reads "success" (required) and "error" (optional).
|
|
/// </summary>
|
|
public class RecNetResult
|
|
{
|
|
[JsonPropertyName("success")]
|
|
public bool Success { get; set; } = true;
|
|
|
|
[JsonPropertyName("error")]
|
|
public string? Error { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// RecNet.Account — dump.cs:567684, Deserialize at RVA 0xF9DE50.
|
|
/// JSON keys verified in the current 2020 IL2CPP build. Account.Deserialize
|
|
/// reads profileImage.
|
|
/// Other keys: accountId, username, displayName, isJunior, platforms. The C# Account class also has
|
|
/// RawUsername and HasBirthday properties but Deserialize does not read
|
|
/// them from JSON (they're set via MakeNameAdhereToPlatformRequirements
|
|
/// or other flows). We expose them with reasonable camelCase keys for
|
|
/// other endpoints that may consume them.
|
|
/// </summary>
|
|
public class RecNetAccount
|
|
{
|
|
private string profileImage = string.Empty;
|
|
|
|
[JsonPropertyName("accountId")]
|
|
public int AccountId { get; set; }
|
|
|
|
[JsonPropertyName("username")]
|
|
public string Username { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("displayName")]
|
|
public string DisplayName { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("profileImage")]
|
|
public string ProfileImage
|
|
{
|
|
get => profileImage;
|
|
set => profileImage = value ?? string.Empty;
|
|
}
|
|
|
|
// Account.Deserialize reads "isJunior" — NOT "treatAsJunior".
|
|
// The C# property name and the JSON key name differ.
|
|
[JsonPropertyName("isJunior")]
|
|
public bool TreatAsJunior { get; set; } = false;
|
|
|
|
// PlatformManager.PlatformMask: Steam=1, Oculus=2, etc.
|
|
[JsonPropertyName("platforms")]
|
|
public int Platforms { get; set; } = 1;
|
|
|
|
// Not in Account.Deserialize body but kept for forward-compat.
|
|
[JsonPropertyName("rawUsername")]
|
|
public string RawUsername { get; set; } = string.Empty;
|
|
|
|
// Likewise.
|
|
[JsonPropertyName("hasBirthday")]
|
|
public bool HasBirthday { get; set; } = true;
|
|
|
|
// 2020.12 Account.Deserialize reads this key (verified via Cpp2IL ISIL
|
|
// dump of CCEOLAOLEKJ.PPGFHEDFBEA — the obfuscated Account class). The
|
|
// 2020.03 client doesn't read it, but emitting it is harmless there.
|
|
// Missing → LitJson throws and 2020.12 surfaces "Malformed Response".
|
|
[JsonPropertyName("createdAt")]
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
|
|
// 2023-03-21 account reader (RecNet.Runtime CICAKEDCJLA / MJKDDBKGNOP /
|
|
// AEGCKMKICFG) registers these keys in three casings each, e.g.
|
|
// "DisplayEmoji"/"displayEmoji"/"displayemoji" (CICAKEDCJLA.txt:1398-1550).
|
|
// Missing keys default on the client, which is why profile emoji,
|
|
// banner, pronouns and identity flags never rendered for anyone.
|
|
private string displayEmoji = string.Empty;
|
|
private string bannerImage = string.Empty;
|
|
|
|
[JsonPropertyName("displayEmoji")]
|
|
public string DisplayEmoji
|
|
{
|
|
get => displayEmoji;
|
|
set => displayEmoji = value ?? string.Empty;
|
|
}
|
|
|
|
[JsonPropertyName("bannerImage")]
|
|
public string BannerImage
|
|
{
|
|
get => bannerImage;
|
|
set => bannerImage = value ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>Pronoun flags enum, serialized as its Int32 value.</summary>
|
|
[JsonPropertyName("personalPronouns")]
|
|
public int PersonalPronouns { get; set; }
|
|
|
|
/// <summary>Identity flags enum, serialized as its Int32 value.</summary>
|
|
[JsonPropertyName("identityFlags")]
|
|
public int IdentityFlags { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// RecNet.SelfAccount : Account — dump.cs:567797, Deserialize at RVA 0xAF4FB0.
|
|
/// Calls base Account.Deserialize, then reads:
|
|
/// email, phone, birthday, juniorState, parentAccountId.
|
|
/// </summary>
|
|
public class RecNetSelfAccount : RecNetAccount
|
|
{
|
|
[JsonPropertyName("email")]
|
|
public string Email { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("phone")]
|
|
public string Phone { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("birthday")]
|
|
public DateTime? Birthday { get; set; } = new DateTime(2000, 1, 1);
|
|
|
|
// RecNet.JuniorState enum (int)
|
|
[JsonPropertyName("juniorState")]
|
|
public int JuniorState { get; set; } = 0;
|
|
|
|
[JsonPropertyName("parentAccountId")]
|
|
public int? ParentAccountId { get; set; } = null;
|
|
|
|
// 2023 self-account reader key (CICAKEDCJLA.txt:1310). An absent key
|
|
// defaults to 0, which the settings UI renders as "no username changes
|
|
// left". DorkNet does not rate-limit username changes, so report a
|
|
// generous allowance.
|
|
[JsonPropertyName("availableUsernameChanges")]
|
|
public int AvailableUsernameChanges { get; set; } = 99;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Accounts.CreateAccountResponse : RecNetResult — dump.cs:568167,
|
|
/// Deserialize at RVA 0xFAA200.
|
|
/// Calls base RecNetResult.Deserialize (reads "success", "error"),
|
|
/// then reads the Account from dict["value"] — NOT dict["account"].
|
|
/// Verified by disassembly: the only string literal after the base
|
|
/// call is "value", passed to Util.GetObjectKey<object>.
|
|
/// </summary>
|
|
public class CreateAccountResponse : RecNetResult
|
|
{
|
|
[JsonPropertyName("value")]
|
|
public RecNetAccount Account { get; set; } = new();
|
|
}
|