Added user login, switching users/tokens, and token validation
This commit is contained in:
@@ -30,28 +30,12 @@ namespace Discord.API
|
|||||||
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
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\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" />
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
BaseClient = new API.DiscordRawClient(_restClientProvider, cancelTokenSource.Token, tokenType, token);
|
var args = new LoginParams { Email = email, Password = password };
|
||||||
BaseClient.SentRequest += (s, e) => _log.Verbose("Rest", $"{e.Method} {e.Endpoint}: {e.Milliseconds} ms");
|
await BaseClient.Login(args).ConfigureAwait(false);
|
||||||
|
await CompleteLogin(cancelTokenSource, false).ConfigureAwait(false);
|
||||||
//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);
|
|
||||||
}
|
}
|
||||||
catch { LogoutInternal(); throw; }
|
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()
|
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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
var nickArgs = new ModifyCurrentUserNickParams { Nickname = args.Nickname.Value };
|
||||||
{
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user