Added user login, switching users/tokens, and token validation
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
12
src/Discord.Net/API/Rest/LoginParams.cs
Normal file
12
src/Discord.Net/API/Rest/LoginParams.cs
Normal 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
src/Discord.Net/API/Rest/LoginResponse.cs
Normal file
10
src/Discord.Net/API/Rest/LoginResponse.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Discord.API.Rest
|
||||
{
|
||||
public class LoginResponse
|
||||
{
|
||||
[JsonProperty("token")]
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user