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

This commit is contained in:
RogueException
2016-05-13 02:54:58 -03:00
parent 9a47de6509
commit 96efc97fc1
7 changed files with 111 additions and 46 deletions

View File

@@ -29,29 +29,13 @@ namespace Discord.API
public TokenType AuthTokenType { get; private set; }
public IRestClient RestClient { 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;
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.SetHeader("accept", "*/*");
_restClient.SetHeader("authorization", authToken);
_restClient.SetHeader("user-agent", DiscordConfig.UserAgent);
_requestQueue = new RequestQueue(_restClient);
@@ -69,6 +53,27 @@ namespace Discord.API
_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
public Task Send(string method, string endpoint, GlobalBucket bucket = GlobalBucket.General)
=> SendInternal(method, endpoint, null, true, bucket);
@@ -122,7 +127,7 @@ namespace Discord.API
stopwatch.Stop();
double milliseconds = ToMilliseconds(stopwatch);
SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
SentRequest?.Invoke(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
return responseStream;
}
@@ -134,11 +139,23 @@ namespace Discord.API
stopwatch.Stop();
double milliseconds = ToMilliseconds(stopwatch);
SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
SentRequest?.Invoke(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds));
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
public async Task<GetGatewayResponse> GetGateway()
{

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; }
}
}

View File

@@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace Discord.API.Rest
{
public class LoginResponse
{
[JsonProperty("token")]
public string Token { get; set; }
}
}

View File

@@ -70,6 +70,8 @@
<Compile Include="API\Optional.cs" />
<Compile Include="API\Rest\DeleteMessagesParam.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\UploadFileParams.cs" />
<Compile Include="API\Rest\GuildPruneParams.cs" />

View File

@@ -14,7 +14,8 @@ namespace Discord
IRestClient RestClient { 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<IChannel> GetChannel(ulong id);

View File

@@ -47,43 +47,64 @@ namespace Discord.Rest
_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);
try
{
await LoginInternal(tokenType, token).ConfigureAwait(false);
await LoginInternal(email, password).ConfigureAwait(false);
}
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)
LogoutInternal();
try
{
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);
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);
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);
BaseClient.SetToken(tokenType, token);
await CompleteLogin(cancelTokenSource, validateToken).ConfigureAwait(false);
}
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()
{
@@ -99,9 +120,14 @@ namespace Discord.Rest
{
bool wasLoggedIn = IsLoggedIn;
try { _cancelTokenSource.Cancel(false); } catch { }
if (_cancelTokenSource != null)
{
try { _cancelTokenSource.Cancel(false); }
catch { }
}
BaseClient = null;
_currentUser = null;
if (wasLoggedIn)
{

View File

@@ -87,10 +87,7 @@ namespace Discord.Rest
bool isCurrentUser = (await Discord.GetCurrentUser().ConfigureAwait(false)).Id == Id;
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);
args.Nickname = new API.Optional<string>(); //Remove
}