Skip to content

Commit 57dac8e

Browse files
authored
Steam OpenID auth linking (#5650)
## Short description <!-- What do you propose to change with your PR? --> Allows players to link and use steam as login option. ## Why we need to add this <!-- What is the reason for adding these changes? Please post links to Discussions as well as Bug Reports here. Please describe how this will change the game balance. --> Some of our users doesn't like discord OAuth, so we're providing better way. ## Checks <!-- check boxes for faster reviewing of your PR --> - [x] I do not require assistance to complete the PR. - [x] Before posting/requesting review of a PR, I have verified that the changes work. - [x] I have added screenshots/videos of the changes, or this PR does not change in-game mechanics. - [x] I affirm that my changes are licensed under the [MIT License](https://github.com/ss14Starlight/space-station-14/blob/Starlight/LICENSE.TXT) and grant permission for use in this repository under its conditions. This PR won't get Changelog, just because it doesn't affect game at all, it affects only Launcher and NullLink, users will get announcement when this will work(currently it just links your steam with your SS14 account, that's all)
1 parent 7c8ee2b commit 57dac8e

20 files changed

Lines changed: 70 additions & 2 deletions

Content.Client/Info/LinkBanner.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ public LinkBanner()
4848
uriOpener.OpenUri(link);
4949
};
5050
buttons.AddChild(button);
51+
52+
var steamButton = new Button { Text = Loc.GetString("server-info-connect-steam-button") };
53+
steamButton.OnPressed += _ => {
54+
var link = _playerRoles.GetSteamLink();
55+
if (link != null)
56+
uriOpener.OpenUri(link);
57+
};
58+
buttons.AddChild(steamButton);
5159
// NullLink end
5260

5361
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();

Content.Client/Options/UI/EscapeMenu.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
99
<Button Access="Public" Name="DiscordButton" Text="{Loc 'ui-escape-connect-discord'}"/>
10+
<Button Access="Public" Name="SteamButton" Text="{Loc 'ui-escape-connect-steam'}"/>
1011
<changelog:ChangelogButton Access="Public" Name="ChangelogButton"/>
1112
<ui:VoteCallMenuButton />
1213
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />

Content.Client/UserInterface/Systems/EscapeMenu/EscapeUIController.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public void OnStateEntered(GameplayState state)
7373
if(_playerRoles.GetDiscordLink() is string link)
7474
_uri.OpenUri(link);
7575
};
76+
77+
_escapeWindow.SteamButton.OnPressed += _ =>
78+
{
79+
if (_playerRoles.GetSteamLink() is string link)
80+
_uri.OpenUri(link);
81+
};
7682
// NullLink end
7783

7884
_escapeWindow.ChangelogButton.OnPressed += _ =>

Content.Client/_NullLink/INullLinkPlayerRolesManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ public interface INullLinkPlayerRolesManager
77

88
bool ContainsAny(ulong[] roles);
99
string? GetDiscordLink();
10+
string? GetSteamLink();
1011
void Initialize();
1112
}

Content.Client/_NullLink/NullLinkPlayerRolesManager.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public sealed partial class NullLinkPlayerRolesManager : INullLinkPlayerRolesMan
1313

1414
private ImmutableHashSet<ulong> _roles = [];
1515
private string? _discordLink;
16+
private string? _steamLink;
1617
private ISawmill _sawmill = default!;
1718

1819
public event Action PlayerRolesChanged = delegate { };
@@ -27,6 +28,7 @@ private void Update(MsgUpdatePlayerRoles message)
2728
{
2829
_roles = message.Roles;
2930
_discordLink = message.DiscordLink;
31+
_steamLink = message.SteamLink;
3032

3133
_sawmill.Info("Updated player roles");
3234
PlayerRolesChanged?.Invoke();
@@ -35,6 +37,9 @@ private void Update(MsgUpdatePlayerRoles message)
3537
public string? GetDiscordLink()
3638
=> _discordLink;
3739

40+
public string? GetSteamLink()
41+
=> _steamLink;
42+
3843
public bool ContainsAny(ulong[] roles)
3944
=> roles.Any(_roles.Contains);
4045
}

Content.Server/_NullLink/PlayerData/INullLinkPlayerManager.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public interface INullLinkPlayerManager
1010
IEnumerable<ICommonSession> Mentors { get; }
1111

1212
string GetDiscordAuthUrl(string customState);
13+
string GetSteamAuthUrl(string customState);
1314
void Initialize();
1415
void Shutdown();
1516
ValueTask SyncPlayTime(PlayerServerPlayTimesSyncEvent playTimesSync);

Content.Server/_NullLink/PlayerData/NullLinkPlayerManager.Linking.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,27 @@ public sealed partial class NullLinkPlayerManager
88
private const string _scope = "identify+guilds+guilds.members.read";
99
private string? _discordKey;
1010
private string? _discordCallback;
11+
private string? _steamAuth;
12+
private string? _steamSecret;
1113
private string? _secret;
1214

1315
public void InitializeLinking()
1416
{
1517
_discordKey = _cfg.GetCVar(StarlightCCVars.DiscordKey).Trim();
1618
_discordCallback = _cfg.GetCVar(StarlightCCVars.DiscordCallback).Trim();
1719
_secret = _cfg.GetCVar(StarlightCCVars.Secret);
20+
_steamAuth = _cfg.GetCVar(StarlightCCVars.SteamBaseUrl);
21+
_steamSecret = _cfg.GetCVar(StarlightCCVars.SteamSecret);
1822

1923
if (!string.IsNullOrEmpty(_discordCallback)
2024
&& (!Uri.TryCreate(_discordCallback, UriKind.Absolute, out var uri)
2125
|| uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
2226
_sawmill.Error($"discord.callback is not a valid absolute http(s) url: '{_discordCallback}'. discord linking will fail. set it to the exact redirect registered in the discord app, e.g. https://your.host/api/auth");
27+
28+
if (!string.IsNullOrEmpty(_steamAuth)
29+
&& (!Uri.TryCreate(_steamAuth, UriKind.Absolute, out var steamUri)
30+
|| steamUri.Scheme != Uri.UriSchemeHttp && steamUri.Scheme != Uri.UriSchemeHttps))
31+
_sawmill.Error($"steam.baseurl is not a valid absolute http(s) url: '{_steamAuth}'. steam linking will fail. set it to the exact redirect registered in api, e.g. https://your.host/api/auth/steam");
2332
}
2433
public string GetDiscordAuthUrl(string customState)
2534
{
@@ -36,4 +45,20 @@ public string GetDiscordAuthUrl(string customState)
3645

3746
return $"https://discord.com/api/oauth2/authorize?client_id={_discordKey}&redirect_uri={Uri.EscapeDataString(_discordCallback)}&response_type=code&scope={_scope}&state={encodedState}";
3847
}
48+
49+
public string GetSteamAuthUrl(string customState)
50+
{
51+
if (string.IsNullOrEmpty(_steamAuth) || string.IsNullOrEmpty(_steamSecret))
52+
return "";
53+
54+
var secretKeyBytes = Encoding.UTF8.GetBytes(_steamSecret);
55+
using var hmac = new HMACSHA256(secretKeyBytes);
56+
57+
var dataBytes = Encoding.UTF8.GetBytes(customState);
58+
var hashBytes = hmac.ComputeHash(dataBytes);
59+
var state = $"{customState}.{BitConverter.ToString(hashBytes).Replace("-", "").ToLower()}";
60+
var encodedState = Uri.EscapeDataString(state);
61+
62+
return $"{_steamAuth}?state={encodedState}";
63+
}
3964
}

Content.Server/_NullLink/PlayerData/NullLinkPlayerManager.Roles.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private void SendPlayerRoles(ICommonSession session, ImmutableHashSet<ulong> rol
4545
=> _netMgr.ServerSendMessage(new MsgUpdatePlayerRoles
4646
{
4747
Roles = roles,
48-
DiscordLink = GetDiscordAuthUrl(session.UserId.ToString())
48+
DiscordLink = GetDiscordAuthUrl(session.UserId.ToString()),
49+
SteamLink = GetSteamAuthUrl(session.UserId.ToString()),
4950
}, session.Channel);
5051
}

Content.Shared/_NullLink/MsgUpdatePlayerRoles.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ public sealed class MsgUpdatePlayerRoles : NetMessage
1010

1111
public ImmutableHashSet<ulong> Roles = [];
1212
public string? DiscordLink;
13+
public string? SteamLink;
1314

1415
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
1516
{
1617
DiscordLink = buffer.ReadString();
18+
SteamLink = buffer.ReadString();
1719

1820
var length = buffer.ReadVariableInt32();
1921
var roles = new HashSet<ulong>(length);
@@ -26,6 +28,7 @@ public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer
2628
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
2729
{
2830
buffer.Write(DiscordLink);
31+
buffer.Write(SteamLink);
2932

3033
buffer.WriteVariableInt32(Roles.Count);
3134
foreach (var role in Roles)

Content.Shared/_Starlight/CCVar/StarlightCCVar.Admin.cs renamed to Content.Shared/_Starlight/CCVar/StarlightCCVars.Admin.cs

File renamed without changes.

0 commit comments

Comments
 (0)