Browse Source

Added user login, switching users/tokens, and token validation

tags/1.0-rc
RogueException 9 years ago
parent
commit
96efc97fc1
7 changed files with 110 additions and 45 deletions
  1. +37
    -20
      src/Discord.Net/API/DiscordRawClient.cs
  2. +12
    -0
      src/Discord.Net/API/Rest/LoginParams.cs
  3. +10
    -0
      src/Discord.Net/API/Rest/LoginResponse.cs
  4. +2
    -0
      src/Discord.Net/Discord.Net.csproj
  5. +2
    -1
      src/Discord.Net/IDiscordClient.cs
  6. +46
    -20
      src/Discord.Net/Rest/DiscordClient.cs
  7. +1
    -4
      src/Discord.Net/Rest/Entities/Users/GuildUser.cs

+ 37
- 20
src/Discord.Net/API/DiscordRawClient.cs View File

@@ -29,29 +29,13 @@ namespace Discord.API
public TokenType AuthTokenType { get; private set; } public TokenType AuthTokenType { get; private set; }
public IRestClient RestClient { get; private set; } public IRestClient RestClient { get; private set; }
public IRequestQueue RequestQueue { get; private set; } public IRequestQueue RequestQueue { get; private set; }
internal DiscordRawClient(RestClientProvider restClientProvider, CancellationToken cancelToken, TokenType authTokenType, string authToken)
internal DiscordRawClient(RestClientProvider restClientProvider, CancellationToken cancelToken)
{ {
_cancelToken = cancelToken; _cancelToken = cancelToken;
AuthTokenType = authTokenType;

switch (authTokenType)
{
case TokenType.Bot:
authToken = $"Bot {authToken}";
break;
case TokenType.Bearer:
authToken = $"Bearer {authToken}";
break;
case TokenType.User:
break;
default:
throw new ArgumentException("Unknown oauth token type", nameof(authTokenType));
}


_restClient = restClientProvider(DiscordConfig.ClientAPIUrl, cancelToken); _restClient = restClientProvider(DiscordConfig.ClientAPIUrl, cancelToken);
_restClient.SetHeader("accept", "*/*"); _restClient.SetHeader("accept", "*/*");
_restClient.SetHeader("authorization", authToken);
_restClient.SetHeader("user-agent", DiscordConfig.UserAgent); _restClient.SetHeader("user-agent", DiscordConfig.UserAgent);
_requestQueue = new RequestQueue(_restClient); _requestQueue = new RequestQueue(_restClient);


@@ -69,6 +53,27 @@ namespace Discord.API
_serializer.ContractResolver = new OptionalContractResolver(); _serializer.ContractResolver = new OptionalContractResolver();
} }


public void SetToken(TokenType tokenType, string token)
{
AuthTokenType = tokenType;

switch (tokenType)
{
case TokenType.Bot:
token = $"Bot {token}";
break;
case TokenType.Bearer:
token = $"Bearer {token}";
break;
case TokenType.User:
break;
default:
throw new ArgumentException("Unknown oauth token type", nameof(tokenType));
}

_restClient.SetHeader("authorization", token);
}

//Core //Core
public Task Send(string method, string endpoint, GlobalBucket bucket = GlobalBucket.General) public Task Send(string method, string endpoint, GlobalBucket bucket = GlobalBucket.General)
=> SendInternal(method, endpoint, null, true, bucket); => SendInternal(method, endpoint, null, true, bucket);
@@ -122,7 +127,7 @@ namespace Discord.API
stopwatch.Stop(); stopwatch.Stop();


double milliseconds = ToMilliseconds(stopwatch); double milliseconds = ToMilliseconds(stopwatch);
SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
SentRequest?.Invoke(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));


return responseStream; return responseStream;
} }
@@ -134,11 +139,23 @@ namespace Discord.API
stopwatch.Stop(); stopwatch.Stop();


double milliseconds = ToMilliseconds(stopwatch); double milliseconds = ToMilliseconds(stopwatch);
SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
SentRequest?.Invoke(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));


return responseStream; return responseStream;
} }



//Auth
public async Task Login(LoginParams args)
{
var response = await Send<LoginResponse>("POST", "auth/login", args).ConfigureAwait(false);
SetToken(TokenType.User, response.Token);
}
public async Task ValidateToken()
{
await Send("GET", "auth/login").ConfigureAwait(false);
}

//Gateway //Gateway
public async Task<GetGatewayResponse> GetGateway() public async Task<GetGatewayResponse> GetGateway()
{ {


+ 12
- 0
src/Discord.Net/API/Rest/LoginParams.cs View File

@@ -0,0 +1,12 @@
using Newtonsoft.Json;

namespace Discord.API.Rest
{
public class LoginParams
{
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
}

+ 10
- 0
src/Discord.Net/API/Rest/LoginResponse.cs View File

@@ -0,0 +1,10 @@
using Newtonsoft.Json;

namespace Discord.API.Rest
{
public class LoginResponse
{
[JsonProperty("token")]
public string Token { get; set; }
}
}

+ 2
- 0
src/Discord.Net/Discord.Net.csproj View File

@@ -70,6 +70,8 @@
<Compile Include="API\Optional.cs" /> <Compile Include="API\Optional.cs" />
<Compile Include="API\Rest\DeleteMessagesParam.cs" /> <Compile Include="API\Rest\DeleteMessagesParam.cs" />
<Compile Include="API\Rest\GetGuildMembersParams.cs" /> <Compile Include="API\Rest\GetGuildMembersParams.cs" />
<Compile Include="API\Rest\LoginParams.cs" />
<Compile Include="API\Rest\LoginResponse.cs" />
<Compile Include="API\Rest\ModifyCurrentUserNickParams.cs" /> <Compile Include="API\Rest\ModifyCurrentUserNickParams.cs" />
<Compile Include="API\Rest\UploadFileParams.cs" /> <Compile Include="API\Rest\UploadFileParams.cs" />
<Compile Include="API\Rest\GuildPruneParams.cs" /> <Compile Include="API\Rest\GuildPruneParams.cs" />


+ 2
- 1
src/Discord.Net/IDiscordClient.cs View File

@@ -14,7 +14,8 @@ namespace Discord
IRestClient RestClient { get; } IRestClient RestClient { get; }
IRequestQueue RequestQueue { get; } IRequestQueue RequestQueue { get; }


Task Login(TokenType tokenType, string token);
Task Login(string email, string password);
Task Login(TokenType tokenType, string token, bool validateToken = true);
Task Logout(); Task Logout();


Task<IChannel> GetChannel(ulong id); Task<IChannel> GetChannel(ulong id);


+ 46
- 20
src/Discord.Net/Rest/DiscordClient.cs View File

@@ -47,43 +47,64 @@ namespace Discord.Rest
_log.Message += (s,e) => Log.Raise(this, e); _log.Message += (s,e) => Log.Raise(this, e);
} }


public async Task Login(TokenType tokenType, string token)
public async Task Login(string email, string password)
{ {
await _connectionLock.WaitAsync().ConfigureAwait(false); await _connectionLock.WaitAsync().ConfigureAwait(false);
try try
{ {
await LoginInternal(tokenType, token).ConfigureAwait(false);
await LoginInternal(email, password).ConfigureAwait(false);
} }
finally { _connectionLock.Release(); } finally { _connectionLock.Release(); }
} }
private async Task LoginInternal(TokenType tokenType, string token)
public async Task Login(TokenType tokenType, string token, bool validateToken = true)
{
await _connectionLock.WaitAsync().ConfigureAwait(false);
try
{
await LoginInternal(tokenType, token, validateToken).ConfigureAwait(false);
}
finally { _connectionLock.Release(); }
}
private async Task LoginInternal(string email, string password)
{ {
if (IsLoggedIn) if (IsLoggedIn)
LogoutInternal(); LogoutInternal();

try try
{ {
var cancelTokenSource = new CancellationTokenSource(); var cancelTokenSource = new CancellationTokenSource();
BaseClient = new API.DiscordRawClient(_restClientProvider, cancelTokenSource.Token, tokenType, token);
BaseClient.SentRequest += (s, e) => _log.Verbose("Rest", $"{e.Method} {e.Endpoint}: {e.Milliseconds} ms");
BaseClient = new API.DiscordRawClient(_restClientProvider, cancelTokenSource.Token);


//MessageQueue = new MessageQueue(RestClient, _restLogger);
//await MessageQueue.Start(_cancelTokenSource.Token).ConfigureAwait(false);
var args = new LoginParams { Email = email, Password = password };
await BaseClient.Login(args).ConfigureAwait(false);
await CompleteLogin(cancelTokenSource, false).ConfigureAwait(false);
}
catch { LogoutInternal(); throw; }
}
private async Task LoginInternal(TokenType tokenType, string token, bool validateToken)
{
if (IsLoggedIn)
LogoutInternal();
try
{
var cancelTokenSource = new CancellationTokenSource();
BaseClient = new API.DiscordRawClient(_restClientProvider, cancelTokenSource.Token);


try
{
var currentUser = await BaseClient.GetCurrentUser().ConfigureAwait(false);
_currentUser = new SelfUser(this, currentUser);
}
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized && tokenType == TokenType.Bearer) { } //Ignore 401 if Bearer doesnt have identity
_cancelTokenSource = cancelTokenSource;
IsLoggedIn = true;
LoggedIn.Raise(this);
BaseClient.SetToken(tokenType, token);
await CompleteLogin(cancelTokenSource, validateToken).ConfigureAwait(false);
} }
catch { LogoutInternal(); throw; } catch { LogoutInternal(); throw; }
} }
private async Task CompleteLogin(CancellationTokenSource cancelTokenSource, bool validateToken)
{
BaseClient.SentRequest += (s, e) => _log.Verbose("Rest", $"{e.Method} {e.Endpoint}: {e.Milliseconds} ms");

if (validateToken)
await BaseClient.ValidateToken().ConfigureAwait(false);

_cancelTokenSource = cancelTokenSource;
IsLoggedIn = true;
LoggedIn.Raise(this);
}


public async Task Logout() public async Task Logout()
{ {
@@ -99,9 +120,14 @@ namespace Discord.Rest
{ {
bool wasLoggedIn = IsLoggedIn; bool wasLoggedIn = IsLoggedIn;


try { _cancelTokenSource.Cancel(false); } catch { }
if (_cancelTokenSource != null)
{
try { _cancelTokenSource.Cancel(false); }
catch { }
}


BaseClient = null; BaseClient = null;
_currentUser = null;


if (wasLoggedIn) if (wasLoggedIn)
{ {


+ 1
- 4
src/Discord.Net/Rest/Entities/Users/GuildUser.cs View File

@@ -87,10 +87,7 @@ namespace Discord.Rest
bool isCurrentUser = (await Discord.GetCurrentUser().ConfigureAwait(false)).Id == Id; bool isCurrentUser = (await Discord.GetCurrentUser().ConfigureAwait(false)).Id == Id;
if (isCurrentUser && args.Nickname.IsSpecified) if (isCurrentUser && args.Nickname.IsSpecified)
{ {
var nickArgs = new ModifyCurrentUserNickParams
{
Nickname = args.Nickname.Value
};
var nickArgs = new ModifyCurrentUserNickParams { Nickname = args.Nickname.Value };
await Discord.BaseClient.ModifyCurrentUserNick(Guild.Id, nickArgs).ConfigureAwait(false); await Discord.BaseClient.ModifyCurrentUserNick(Guild.Id, nickArgs).ConfigureAwait(false);
args.Nickname = new API.Optional<string>(); //Remove args.Nickname = new API.Optional<string>(); //Remove
} }


Loading…
Cancel
Save