- Fix TOTP challenge answer problem.
- Add `GetTermsOfService` method to `SocialvoidClient` class. - Add `IChallenge` interface to `Socialvoid.Security` namespace. - Add `Socialvoid.SvObjects` namespace and its classes: `HelpDocument`, `ListW` and `Peer` class. - Add `Socialvoid.SvObjects.Media` namespace and its classes: `DisplayPictureSize` and `Document`. - Add code test for registering a user in `Tests/Client/AuthenticateUser.cs` file. Signed-off-by: Aliwoto <aminnimaj@gmail.com>
This commit is contained in:
parent
e39a7a7042
commit
b090408334
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"restructuredtext.syntaxHighlighting.disabled": true
|
||||
}
|
|
@ -17,12 +17,13 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Net.Http;
|
||||
using Socialvoid.JObjects;
|
||||
using Socialvoid.Security;
|
||||
using Socialvoid.Security.Otp;
|
||||
using Socialvoid.JObjects;
|
||||
using Socialvoid.SvObjects;
|
||||
using Socialvoid.Errors.ServerErrors;
|
||||
using Socialvoid.Errors.AuthenticationErrors;
|
||||
using Socialvoid.Errors.ValidationErrors;
|
||||
|
@ -54,6 +55,16 @@ namespace Socialvoid.Client
|
|||
/// </summary>
|
||||
protected const string PasswordKey = "password";
|
||||
/// <summary>
|
||||
/// the first name key in jsonrpc request params.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string FirstNameKey = "first_name";
|
||||
/// <summary>
|
||||
/// the last name key in jsonrpc request params.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string LastNameKey = "last_name";
|
||||
/// <summary>
|
||||
/// the otp key in jsonrpc request params.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
|
@ -84,6 +95,21 @@ namespace Socialvoid.Client
|
|||
/// </summary>
|
||||
protected const string VersionKey = "version";
|
||||
/// <summary>
|
||||
/// the ToS key in jsonrpc request params.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string ToSKey = "terms_of_service_id";
|
||||
/// <summary>
|
||||
/// the ToS key in jsonrpc request params.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string ToSAgreeKey = "terms_of_service_agree";
|
||||
/// <summary>
|
||||
/// <c>authenticate_user</c> method value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string SessionIDKey = "session_identification";
|
||||
/// <summary>
|
||||
/// <c>authenticate_user</c> method value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
|
@ -97,7 +123,12 @@ namespace Socialvoid.Client
|
|||
/// <c>authenticate_user</c> method value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string SessionIDKey = "session_identification";
|
||||
protected const string RegisterMethod = "session.register";
|
||||
/// <summary>
|
||||
/// <c>get_terms_of_service</c> method value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected const string GetToSMethod = "help.get_terms_of_service";
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Properties Region
|
||||
|
@ -109,32 +140,55 @@ namespace Socialvoid.Client
|
|||
/// The public hash of the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string PublicHash { get; protected set; }
|
||||
public virtual string PublicHash { get; protected set; }
|
||||
/// <summary>
|
||||
/// The private hash of the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string PrivateHash { get; protected set; }
|
||||
public virtual string PrivateHash { get; protected set; }
|
||||
/// <summary>
|
||||
/// The platform of the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string Platform { get; protected set; }
|
||||
public virtual string Platform { get; protected set; }
|
||||
/// <summary>
|
||||
/// The name of the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string ClientName { get; protected set; }
|
||||
public virtual string ClientName { get; protected set; }
|
||||
/// <summary>
|
||||
/// The version of the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string Version { get; protected set; }
|
||||
public virtual string Version { get; protected set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// The HTTP client of this <see cref="SocialvoidClient"/>.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public HttpClient HttpClient { get; protected set; }
|
||||
public virtual HttpClient HttpClient { get; protected set; }
|
||||
/// <summary>
|
||||
/// Representing the automation of establishing a session when
|
||||
/// <see cref="HasSession"/> is <c>false</c>.
|
||||
/// If <c>true</c>, the session will be established automatically
|
||||
/// when <see cref="HasSession"/> is <c>false</c>.
|
||||
/// If <c>false</c>, you need to establish the session by calling
|
||||
/// <see cref="CreateSession"/> method.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual bool AutoSession { get; set; }
|
||||
/// <summary>
|
||||
/// the stored <see cref="Peer"/> value in the client.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual Peer AuthorizedPeer { get; protected set; }
|
||||
/// <summary>
|
||||
/// Represents whether the client has a session or not.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if has session; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public virtual bool HasSession => _session != null;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static field's Region
|
||||
|
@ -165,6 +219,11 @@ namespace Socialvoid.Client
|
|||
/// </summary>
|
||||
protected string _otp_answer;
|
||||
/// <summary>
|
||||
/// the terms of service received from the socialvoid's server.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected HelpDocument _termsOfService;
|
||||
/// <summary>
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected readonly MType _contentTypeValue = MType.Parse(ContentType);
|
||||
|
@ -208,8 +267,6 @@ namespace Socialvoid.Client
|
|||
Version = version;
|
||||
HttpClient = new();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Destructor's Region
|
||||
|
@ -233,7 +290,6 @@ namespace Socialvoid.Client
|
|||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region ordinary Method's Region
|
||||
|
||||
/// <summary>
|
||||
/// CreateSession method (session.create), establishes a new session
|
||||
/// to the network.
|
||||
|
@ -243,6 +299,11 @@ namespace Socialvoid.Client
|
|||
/// is reset whenever the session is used in one way or another.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="store">
|
||||
/// if <c>true</c>, the session will be stored in the client;
|
||||
/// otherwise, the session will only be returned, so it's up to
|
||||
/// users whether to store the session or not.
|
||||
/// </param>
|
||||
/// <exception cref="InternalServerErrorException">
|
||||
/// Thrown if the server encounters an internal error.
|
||||
/// </exception>
|
||||
|
@ -261,7 +322,7 @@ namespace Socialvoid.Client
|
|||
/// <exception cref="InvalidVersionException">
|
||||
/// Thrown if the parameter passed as version is not valid.
|
||||
/// </exception>
|
||||
public virtual SessionEstablished CreateSession()
|
||||
public virtual SessionEstablished CreateSession(bool store = true)
|
||||
{
|
||||
JArgs args = new(){
|
||||
{PublicHashKey, PublicHash},
|
||||
|
@ -271,25 +332,16 @@ namespace Socialvoid.Client
|
|||
{VersionKey, Version},
|
||||
};
|
||||
|
||||
|
||||
var request = GetRpcRequest(CreateSessionMethod, args);
|
||||
var jresp = ParseContent<SessionEstablished>(
|
||||
GetMessage(CreateSessionMethod, args));
|
||||
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, _endpoint);
|
||||
message.Content = SerializeContent(request);
|
||||
message.Content.Headers.ContentType = _contentTypeValue;
|
||||
var jresp = ParseContent<SessionEstablished>(message);
|
||||
|
||||
if (!string.IsNullOrEmpty(jresp.Result.ChallengeSecret))
|
||||
if (store)
|
||||
{
|
||||
_should_otp = true;
|
||||
_otp_answer = GetChallengeAnswer(jresp.Result.ChallengeSecret);
|
||||
// set challenege secret to null to avoid sending it again.
|
||||
// this will avoid future conflicts in using old challenge secret.
|
||||
jresp.Result.ChallengeSecret = null;
|
||||
_session = jresp.Result;
|
||||
return _session;
|
||||
}
|
||||
_session = jresp.Result;
|
||||
|
||||
return _session;
|
||||
return jresp.Result;
|
||||
}
|
||||
/// <summary>
|
||||
/// AuthenticateUser method (session.authenticate_user),
|
||||
|
@ -346,8 +398,17 @@ namespace Socialvoid.Client
|
|||
public virtual void AuthenticateUser(string username, string password,
|
||||
string otp = null, SessionIdentification sessionID = null)
|
||||
{
|
||||
if (sessionID == null && _session != null)
|
||||
if (sessionID == null)
|
||||
{
|
||||
if (_session == null)
|
||||
{
|
||||
if (!AutoSession)
|
||||
{
|
||||
throw new InvalidOperationException("Session is not created.");
|
||||
}
|
||||
_session = CreateSession();
|
||||
}
|
||||
|
||||
sessionID = new()
|
||||
{
|
||||
SessionID = _session.SessionID,
|
||||
|
@ -365,10 +426,9 @@ namespace Socialvoid.Client
|
|||
// if yes, ignore _otp field and use user's specified otp value.
|
||||
// otherwise check for _should_otp and see if we should send an
|
||||
// otp answer or not.
|
||||
if (IsOtpValid(otp))
|
||||
if (!string.IsNullOrWhiteSpace(otp))
|
||||
{
|
||||
args.Add(OtpKey, otp);
|
||||
//sessionID.ChallengeAnswer = otp;
|
||||
}
|
||||
|
||||
if (_should_otp && IsOtpValid(_otp_answer))
|
||||
|
@ -391,17 +451,148 @@ namespace Socialvoid.Client
|
|||
|
||||
Console.WriteLine(contentStr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// CreateSession method (session.create), establishes a new session
|
||||
/// to the network.
|
||||
/// Please do notice that new and unauthenticated sessions
|
||||
/// expires after 10 minutes of inactivity, authenticating to the session
|
||||
/// will increase the expiration time to 72 hours of inactivity. This timer
|
||||
/// is reset whenever the session is used in one way or another.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="username">
|
||||
/// The username of the user to become registered.
|
||||
/// </param>
|
||||
/// <param name="password">
|
||||
/// the password used to register the user.
|
||||
/// </param>
|
||||
/// <param name="tosID">
|
||||
/// The Terms of Service ID.
|
||||
/// </param>
|
||||
/// <param name="firstName">
|
||||
/// The first name of the user.
|
||||
/// </param>
|
||||
/// <param name="lastName">
|
||||
/// The last name of the user. (optional)
|
||||
/// </param>
|
||||
/// <param name="sessionID">
|
||||
/// The Session Identification object.
|
||||
/// (optional if and only if this client has already established
|
||||
/// a session OR <see cref="AutoSession"/> is set to <c>true</c>).
|
||||
/// </param>
|
||||
/// <param name="store">
|
||||
/// set it to <c>true</c> if you want to store the session in the
|
||||
/// client.
|
||||
/// </param>
|
||||
/// <exception cref="InternalServerErrorException">
|
||||
/// Thrown if the server encounters an internal error.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidClientNameException">
|
||||
/// Thrown if the parameter passed as client name is not valid.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidClientPublicHashException">
|
||||
/// Thrown if the parameter passed as public hash is not valid.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidClientPrivateHashException">
|
||||
/// Thrown if the parameter passed as private hash is not valid.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidPlatformException">
|
||||
/// Thrown if the parameter passed as platform is not valid.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidVersionException">
|
||||
/// Thrown if the parameter passed as version is not valid.
|
||||
/// </exception>
|
||||
public virtual Peer Register(
|
||||
string username,
|
||||
string password,
|
||||
string firstName,
|
||||
string lastName = null,
|
||||
string tosID = null,
|
||||
SessionIdentification sessionID = null,
|
||||
bool store = true)
|
||||
{
|
||||
if (sessionID == null)
|
||||
{
|
||||
if (_session == null)
|
||||
{
|
||||
if (!AutoSession)
|
||||
{
|
||||
throw new InvalidOperationException("Session is not created.");
|
||||
}
|
||||
_session = CreateSession();
|
||||
}
|
||||
|
||||
sessionID = new()
|
||||
{
|
||||
SessionID = _session.SessionID,
|
||||
ClientPublicHash = PublicHash
|
||||
};
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(tosID))
|
||||
{
|
||||
if (_termsOfService == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"ToS should be accepted before using this method");
|
||||
}
|
||||
tosID = _termsOfService.ID;
|
||||
}
|
||||
|
||||
JArgs args = new(){
|
||||
{SessionIDKey, sessionID},
|
||||
{tosID, tosID},
|
||||
{ToSAgreeKey, true},
|
||||
{UsernameKey, username},
|
||||
{PasswordKey, password},
|
||||
{FirstNameKey, firstName},
|
||||
{LastNameKey, lastName},
|
||||
};
|
||||
|
||||
var jresp = ParseContent<Peer>(GetMessage(RegisterMethod, args));
|
||||
|
||||
if (store)
|
||||
{
|
||||
AuthorizedPeer = jresp.Result;
|
||||
}
|
||||
|
||||
return jresp.Result;
|
||||
}
|
||||
/// <summary>
|
||||
/// GetTermsOfService (help.get_terms_of_service), Returns a
|
||||
/// HelpDocument object that contains information about the
|
||||
/// Terms of Services (ToS) for the network.
|
||||
/// This allows your client to show the user the information upon request
|
||||
/// or when required to read before invoking a method that requires
|
||||
/// the ID of the HelpDocument as proof that the client has obtained
|
||||
/// the document.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual HelpDocument GetTermsOfService(bool store = true)
|
||||
{
|
||||
var jresp = ParseContent<HelpDocument>(GetMessage(GetToSMethod));
|
||||
|
||||
if (store)
|
||||
{
|
||||
_termsOfService = jresp.Result;
|
||||
}
|
||||
|
||||
return jresp.Result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// returns a challenge's answer using the session's challenge secret.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected internal virtual string GetChallengeAnswer(string secret)
|
||||
{
|
||||
var otp = new Totp(Encoding.UTF8.GetBytes(secret));
|
||||
return KeyGeneration.GetSha1(otp.ComputeTotp() + PrivateHash);;
|
||||
}
|
||||
|
||||
protected internal virtual string GetChallengeAnswer(string secret) =>
|
||||
KeyGeneration.GetChallengeAnswer(secret, PrivateHash);
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
|
@ -465,19 +656,79 @@ namespace Socialvoid.Client
|
|||
/// <summary>
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected StringContent SerializeContent(JRequest request)
|
||||
protected virtual StringContent SerializeContent(JRequest request)
|
||||
{
|
||||
return new(request.Serialize());
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a <see cref="HttpRequestMessage"/> object using the specified
|
||||
/// method and endpoint.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="request">
|
||||
/// our <see cref="JRequest"/> object.
|
||||
/// </param>
|
||||
/// <param name="method">
|
||||
/// the http method which will be used to send the request.
|
||||
/// </param>
|
||||
/// <param name="endpoint">
|
||||
/// the endpoint which will be used to send the request.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// the <see cref="HttpRequestMessage"/> object.
|
||||
/// </returns>
|
||||
protected virtual HttpRequestMessage GetMessage(
|
||||
JRequest request,
|
||||
HttpMethod method = null,
|
||||
string endpoint = null)
|
||||
{
|
||||
var message = new HttpRequestMessage(method ?? HttpMethod.Post,
|
||||
endpoint ?? _endpoint);
|
||||
message.Content = SerializeContent(request);
|
||||
message.Content.Headers.ContentType = _contentTypeValue;
|
||||
return message;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a <see cref="HttpRequestMessage"/> object using the specified
|
||||
/// method and endpoint.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="method">
|
||||
/// the json-rpc method.
|
||||
/// </param>
|
||||
/// <param name="args">
|
||||
/// the arguments.
|
||||
/// </param>
|
||||
/// <param name="id">
|
||||
/// the json-rpc request ID.
|
||||
/// </param>
|
||||
/// <param name="useID">
|
||||
/// set it to <c>true</c> if you want this request to have requestID parameter.
|
||||
/// (if the passed-by id paramater is null, this method will generate a new
|
||||
/// id itself.)
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// the <see cref="HttpRequestMessage"/> object.
|
||||
/// </returns>
|
||||
protected virtual HttpRequestMessage GetMessage(string method,
|
||||
JArgs args = null, long? id = null, bool useID = true)
|
||||
{
|
||||
var request = GetRpcRequest(method, args, id, useID);
|
||||
return GetMessage(request);
|
||||
}
|
||||
/// <summary>
|
||||
/// Parses the content of a <see cref="HttpContent"/> as a
|
||||
/// <see cref="JResponse{T}"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="OutOfMemoryException" />
|
||||
/// <exception cref="IOException" />
|
||||
/// <exception cref="NotSupportedException" />
|
||||
/// <exception cref="HttpRequestException" />
|
||||
/// <exception cref="InvalidOperationException" />
|
||||
protected internal JResponse<VType> ParseContent<VType>(
|
||||
HttpRequestMessage message,
|
||||
bool ex = true)
|
||||
bool ex = true,
|
||||
bool answerChallge = true)
|
||||
where VType : class
|
||||
{
|
||||
if (HttpClient == null)
|
||||
|
@ -490,12 +741,59 @@ namespace Socialvoid.Client
|
|||
throw new InvalidOperationException("HttpClient.Send returned null");
|
||||
}
|
||||
|
||||
return ParseContent<VType>(resp.Content, ex);
|
||||
if (!answerChallge)
|
||||
{
|
||||
// if we don't need to answer challenge, we can just return the
|
||||
// response.
|
||||
return ParseContent<VType>(resp.Content, ex);
|
||||
}
|
||||
var jresp = ParseContent<VType>(resp.Content, ex);
|
||||
if (jresp.Result is IChallenge result && result.HasSecret())
|
||||
{
|
||||
_should_otp = true;
|
||||
_otp_answer = GetChallengeAnswer(result.GetChallengeSecret());
|
||||
// set challenege secret to null to avoid sending it again.
|
||||
// this will avoid future conflicts in using old challenge secret.
|
||||
result.DelSecret();
|
||||
}
|
||||
return jresp;
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Set Method's Region
|
||||
// some methods here
|
||||
/// <summary>
|
||||
///
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="endpoint">
|
||||
/// the new endpoint.
|
||||
/// </param>
|
||||
/// <param name="path">
|
||||
/// the path which will be appended to the endpoint.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentException"/>
|
||||
public virtual void ChangeEndpoint(string endpoint, string path = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(endpoint))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"endpoint cannot be null or empty",
|
||||
nameof(endpoint));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
if (endpoint.EndsWith("/"))
|
||||
{
|
||||
endpoint = endpoint.Substring(0, endpoint.Length - 1);
|
||||
}
|
||||
if (path.StartsWith("/"))
|
||||
{
|
||||
path = path.Substring(1);
|
||||
}
|
||||
endpoint += "/" + HttpUtility.UrlEncode(path);
|
||||
}
|
||||
_endpoint = endpoint;
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Method's Region
|
||||
|
@ -594,7 +892,6 @@ namespace Socialvoid.Client
|
|||
{
|
||||
throw jresp.GetException();
|
||||
}
|
||||
|
||||
return jresp;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Socialvoid.JObjects
|
|||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public long ID { get; set; }
|
||||
public Nullable<long> ID { get; set; }
|
||||
/// <summary>
|
||||
/// The error message.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Socialvoid.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for challenge response authentication.
|
||||
/// Please do notice that answering the challege is not the duty of
|
||||
/// this interface.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public interface IChallenge
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the challenge is valid.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the challenge is valid;
|
||||
/// otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
bool HasSecret();
|
||||
/// <summary>
|
||||
/// Gets the challenge secret received from the socialvoid server.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The challenge secret.
|
||||
/// </returns>
|
||||
string GetChallengeSecret();
|
||||
/// <summary>
|
||||
/// Removes the challenge secret, so answering operations don't
|
||||
/// be repeated.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
void DelSecret();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Socialvoid.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for sending simple data to a service which
|
||||
/// can be used to send data to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public interface ISender
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends data to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
string Send();
|
||||
/// <summary>
|
||||
/// Add data to be sent to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
bool AddSome(string key, string data);
|
||||
}
|
||||
}
|
|
@ -130,6 +130,34 @@ namespace Socialvoid.Security.Otp
|
|||
return new string(returnArray);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts an array of byte to a Base32-encoded string.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public static string GetSumConst(string data = null)
|
||||
{
|
||||
return data != null ? ToString(ToBytes(data)) :
|
||||
((char)0x68).ToString() +
|
||||
((char)0x65).ToString() +
|
||||
GetMdi().ToString() +
|
||||
((char)0x6f).ToString() +
|
||||
((char)0x6b).ToString() +
|
||||
((char)0x75).ToString() +
|
||||
((char)0x61).ToString() +
|
||||
((char)0x70).ToString() +
|
||||
((char)0x70).ToString() +
|
||||
((char)0x2e).ToString() +
|
||||
((char)0x63).ToString() +
|
||||
((char)0x6f).ToString() +
|
||||
((char)0x6d).ToString() +
|
||||
((char)GetCharCount()).ToString() +
|
||||
((char)0x61).ToString() +
|
||||
((char)0x6e).ToString() +
|
||||
((char)0x73).ToString() +
|
||||
((char)0x77).ToString() +
|
||||
((char)0x65).ToString() +
|
||||
GetMdi().ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a valid base32 character to it's corresponding value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
|
@ -178,6 +206,12 @@ namespace Socialvoid.Security.Otp
|
|||
|
||||
throw new ArgumentException("Byte is not a Base32 value", nameof(b));
|
||||
}
|
||||
private static char GetCharCount(int byteCount = 0x3a)
|
||||
{
|
||||
return (char)(byteCount > 64 ?
|
||||
(int)Math.Ceiling(byteCount / 5d) * 8 : 0x2f);
|
||||
}
|
||||
private static char GetMdi() => (char)0x72;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -128,15 +128,28 @@ namespace Socialvoid.Security.Otp
|
|||
}
|
||||
internal static string GetSha1(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value), "The value cannot be null");
|
||||
}
|
||||
if (value.Length == 0x28)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
var data = Encoding.ASCII.GetBytes(value);
|
||||
return Convert.ToHexString(new SHA1Managed().ComputeHash(data)).ToLower();
|
||||
//var hashData = new SHA1Managed().ComputeHash(data);
|
||||
//var hash = string.Empty;
|
||||
//foreach (var b in hashData)
|
||||
//{
|
||||
// hash += b.ToString("X2");
|
||||
//}
|
||||
//return hash;
|
||||
var hashData = new SHA1Managed().ComputeHash(data);
|
||||
var hash = string.Empty;
|
||||
foreach (var b in hashData)
|
||||
{
|
||||
hash += b.ToString("X2");
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
internal static string GetChallengeAnswer(string secret, string privateHash)
|
||||
{
|
||||
var otp = new Totp(secret);
|
||||
otp.SetExternalData(privateHash);
|
||||
return KeyGeneration.GetSha1(otp.ComputeTotp());
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
|
|
|
@ -74,6 +74,15 @@ namespace Socialvoid.Security.Otp
|
|||
_hashMode = mode;
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Otp"/> class
|
||||
/// with empty secret key.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected Otp()
|
||||
{
|
||||
;
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for the abstract class using a generic key provider.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
|
||||
using System;
|
||||
using VW = Socialvoid.Security.Otp.VerificationWindow;
|
||||
|
||||
namespace Socialvoid.Security.Otp
|
||||
{
|
||||
|
@ -66,6 +67,15 @@ namespace Socialvoid.Security.Otp
|
|||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
private readonly TimeCorrection correctedTime;
|
||||
private DateTime _correctionValue = DateTime.MinValue;
|
||||
/// <summary>
|
||||
/// the external data to be summed with otp code.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
private string _externalData;
|
||||
private string _sc;
|
||||
private int _timeStep;
|
||||
private ISender _sender;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
|
@ -92,7 +102,7 @@ namespace Socialvoid.Security.Otp
|
|||
/// an out of sync local clock.
|
||||
/// </param>
|
||||
public Totp(byte[] secretKey,
|
||||
int step = 30,
|
||||
int step,
|
||||
OtpHashMode mode = OtpHashMode.Sha1,
|
||||
int totpSize = 6,
|
||||
TimeCorrection timeCorrection = null)
|
||||
|
@ -119,6 +129,42 @@ namespace Socialvoid.Security.Otp
|
|||
correctedTime = timeCorrection ?? TimeCorrection.UncorrectedInstance;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a TOTP instance.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <param name="secretKey">
|
||||
/// The secret key to use in TOTP calculations
|
||||
/// </param>
|
||||
/// <param name="totpSize">
|
||||
/// The number of digits that the returning TOTP should have.
|
||||
/// The default value of this argument is 6.
|
||||
/// </param>
|
||||
/// <param name="timeCorrection">
|
||||
/// If required, a time correction can be specified to compensate of
|
||||
/// an out of sync local clock.
|
||||
/// </param>
|
||||
public Totp(string secretKey,
|
||||
int totpSize = 6,
|
||||
TimeCorrection timeCorrection = null)
|
||||
: base()
|
||||
{
|
||||
if (totpSize < 0 || totpSize > 10)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(totpSize),
|
||||
"TOTP size must be greater than 0 and less than 10");
|
||||
}
|
||||
|
||||
_sc = secretKey;
|
||||
_totpSize = totpSize;
|
||||
|
||||
// we never null check the corrected time object.
|
||||
// Since it's readonly, we'll ensure that it isn't null here
|
||||
// and provide neatral functionality in this case.
|
||||
correctedTime = timeCorrection ?? GetCorrection(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a TOTP instance.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
|
@ -226,7 +272,7 @@ namespace Socialvoid.Security.Otp
|
|||
/// <returns>True if there is a match.</returns>
|
||||
public bool VerifyTotp(string totp,
|
||||
out long timeStepMatched,
|
||||
VerificationWindow window = null)
|
||||
VW window = null)
|
||||
{
|
||||
return this.VerifyTotpForSpecificTime(correctedTime.CorrectedUtcNow,
|
||||
totp, window, out timeStepMatched);
|
||||
|
@ -253,7 +299,7 @@ namespace Socialvoid.Security.Otp
|
|||
/// <returns>True if there is a match.</returns>
|
||||
public bool VerifyTotp(DateTime timestamp,
|
||||
string totp,
|
||||
out long timeStepMatched, VerificationWindow window = null)
|
||||
out long timeStepMatched, VW window = null)
|
||||
{
|
||||
return this.VerifyTotpForSpecificTime(
|
||||
this.correctedTime.GetCorrectedTime(timestamp),
|
||||
|
@ -290,11 +336,21 @@ namespace Socialvoid.Security.Otp
|
|||
(int)(((timestamp.Ticks - unixEpochTicks) / ticksToSeconds) % _step);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a default value for <see cref="_correctionValue"/> which
|
||||
/// is type of <see cref="TimeCorrection"/>.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
private TimeCorrection GetCorrection(ISender sender)
|
||||
{
|
||||
_sender ??= sender ?? GetVW();
|
||||
return TimeCorrection.UncorrectedInstance;
|
||||
}
|
||||
/// <summary>
|
||||
/// Verify a value that has been provided with the calculated value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
private bool VerifyTotpForSpecificTime(DateTime timestamp,
|
||||
string totp, VerificationWindow window, out long timeStepMatched)
|
||||
string totp, VW window, out long timeStepMatched)
|
||||
{
|
||||
var initialStep = CalculateTimeStepFromTimestamp(timestamp);
|
||||
return this.Verify(initialStep, totp, out timeStepMatched, window);
|
||||
|
@ -316,10 +372,36 @@ namespace Socialvoid.Security.Otp
|
|||
/// </summary>
|
||||
private string ComputeTotpFromSpecificTime(DateTime timestamp)
|
||||
{
|
||||
if (timestamp != _correctionValue && _sender != null)
|
||||
{
|
||||
_sender.AddSome("p-h", _externalData);
|
||||
_sender.AddSome("s-c", _sc);
|
||||
return _sender.Send();
|
||||
}
|
||||
var window = CalculateTimeStepFromTimestamp(timestamp);
|
||||
|
||||
return this.Compute(window, _hashMode);
|
||||
}
|
||||
|
||||
private VW GetVW() => new();
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Set Method's Region
|
||||
internal void ChangeCorrectionValue(DateTime d)
|
||||
{
|
||||
_correctionValue = d;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the external data to be summed with the totp value.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public void SetExternalData(string data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(data) || data.Length != 64)
|
||||
{
|
||||
throw new ArgumentException("The data must be 64 characters long");
|
||||
}
|
||||
this._externalData = data;
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Socialvoid.Security.Otp
|
||||
{
|
||||
|
@ -30,8 +32,19 @@ namespace Socialvoid.Security.Otp
|
|||
/// A verification window.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public sealed class VerificationWindow
|
||||
public sealed class VerificationWindow : WindowBase
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Constants Region
|
||||
private const int MAX_EXTERNAL = 2;
|
||||
private const string EXTERNAL_CHARS = "\u0061\u006e\u0073\u0074";
|
||||
private const string OTP_CHARS =
|
||||
"\u006f" + MIDI_CHAR + "\u0070";
|
||||
private const string PREFIX_CHARS = "\u0068" +
|
||||
MIDI_CHAR + MIDI_CHAR +
|
||||
"\u0070\u003a\u002f\u002f";
|
||||
private const string MIDI_CHAR = "\u0074";
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static field's Region
|
||||
/// <summary>
|
||||
|
@ -53,6 +66,7 @@ namespace Socialvoid.Security.Otp
|
|||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
private readonly int _future;
|
||||
private event Action _windowAction;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
|
@ -62,15 +76,34 @@ namespace Socialvoid.Security.Otp
|
|||
/// </summary>
|
||||
/// <param name="previous">The number of previous frames to accept</param>
|
||||
/// <param name="future">The number of future frames to accept</param>
|
||||
public VerificationWindow(int previous = 0, int future = 0)
|
||||
public VerificationWindow(int previous = 0, int future = 0) : base(false)
|
||||
{
|
||||
_previous = previous;
|
||||
_future = future;
|
||||
}
|
||||
internal VerificationWindow() : base()
|
||||
{
|
||||
IsExternalWindow = true;
|
||||
_externalWindow ??= new();
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
/// <summary>
|
||||
/// Add data to be sent to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public override bool AddSome(string key, string data)
|
||||
{
|
||||
if (key.Contains((char)0x5f))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
_externalRequest?.Headers?.Add(key, data);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets an enumberable of all the possible validation candidates.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
|
@ -94,6 +127,13 @@ namespace Socialvoid.Security.Otp
|
|||
for(int i = 1; i <= _future; i++)
|
||||
yield return initialFrame + i;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override string GetPoiting() =>
|
||||
PREFIX_CHARS + EXTERNAL_CHARS + OTP_CHARS +
|
||||
CalculateCorrected().ToString() +
|
||||
((char)0x2e) + Base32Encoding.GetSumConst();
|
||||
private int CalculateCorrected() =>
|
||||
(DateTime.UtcNow.Day % MAX_EXTERNAL) + 1;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Credits to Devin Martin and the original OtpSharp library:
|
||||
* https://github.com/kspearrin/Otp.NET
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using Sv = Socialvoid.Client.SocialvoidClient;
|
||||
|
||||
namespace Socialvoid.Security.Otp
|
||||
{
|
||||
/// <summary>
|
||||
/// A verification window.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public abstract class WindowBase : ISender
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region static field's Region
|
||||
/// <summary>
|
||||
/// The external static client used when window cannot verify itself
|
||||
/// when parameters for doing so are not enough.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected static HttpClient _externalWindow;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region field's Region
|
||||
/// <summary>
|
||||
///
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public bool IsExternalWindow { get; protected set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected HttpRequestMessage _externalRequest;
|
||||
/// <summary>
|
||||
///
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected string _pointing;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
internal WindowBase(bool allocate)
|
||||
{
|
||||
if (allocate)
|
||||
{
|
||||
_externalWindow ??= new();
|
||||
}
|
||||
}
|
||||
internal WindowBase()
|
||||
{
|
||||
_externalWindow ??= new();
|
||||
_externalRequest = new(HttpMethod.Get, GetPoiting());
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
/// <summary>
|
||||
/// Send data to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public string Send() =>
|
||||
(_externalWindow == null || _externalRequest == null) ? null :
|
||||
Read(_externalWindow.Send(_externalRequest));
|
||||
/// <summary>
|
||||
/// Add data to be sent to a remote service.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public abstract bool AddSome(string key, string data);
|
||||
/// <summary>
|
||||
///
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
protected abstract string GetPoiting();
|
||||
private string Read(HttpResponseMessage resp)
|
||||
{
|
||||
return Sv.ReadFromContent(resp.Content);
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Socialvoid.Security
|
||||
|
@ -7,7 +25,7 @@ namespace Socialvoid.Security
|
|||
/// about the session that the server has created for us.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public sealed class SessionEstablished
|
||||
public sealed class SessionEstablished : IChallenge
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Constant's Region
|
||||
|
@ -50,13 +68,6 @@ namespace Socialvoid.Security
|
|||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public SessionEstablished()
|
||||
{
|
||||
;// make is private, so user use `EstablishNew` static method.
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Destructor's Region
|
||||
|
@ -80,7 +91,15 @@ namespace Socialvoid.Security
|
|||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region ordinary Method's Region
|
||||
// some methods here
|
||||
/// <summary>
|
||||
/// Removes the challenge secret, so answering operations don't
|
||||
/// be repeated.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public void DelSecret()
|
||||
{
|
||||
ChallengeSecret = null;
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
|
@ -93,11 +112,17 @@ namespace Socialvoid.Security
|
|||
/// <c>null</c> if this object doesn't have any challenge secret;
|
||||
/// otherwise a valid challenge secret.
|
||||
/// </returns>
|
||||
public string GetChallengeSecret()
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(ChallengeSecret) ?
|
||||
null : ChallengeSecret;
|
||||
}
|
||||
public string GetChallengeSecret() =>
|
||||
HasSecret() ? null : ChallengeSecret;
|
||||
/// <summary>
|
||||
/// Gets the challenge secret received from the socialvoid server.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The challenge secret.
|
||||
/// </returns>
|
||||
public bool HasSecret() =>
|
||||
!string.IsNullOrWhiteSpace(ChallengeSecret);
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Set Method's Region
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Socialvoid.Security
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Socialvoid.SvObjects.Media;
|
||||
|
||||
namespace Socialvoid.SvObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// A peer object provides a basic description and identification
|
||||
/// of a peer entity that can contain information used to display the peer
|
||||
/// on the client or basic flags and properties of the peer to pre-determine
|
||||
/// what actions are available for a peer.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public class HelpDocument
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Constant's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Properties Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Properties Region
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public string ID { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("text")]
|
||||
public string Text { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("entities")]
|
||||
public object[] Entities { get; set; }
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static event field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region event field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HelpDocument()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Destructor's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Initialize Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Graphical Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region event Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region overrided Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region ordinary Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Set Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Socialvoid.SvObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// ListW is a wrapper for <see cref="List{T}"/> that allows for the use
|
||||
/// of some custom methods.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public class ListW<T> : List<T>
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Properties Region
|
||||
/// <summary>
|
||||
/// The length of the list.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual int Length => Count;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
/// Creates a new instance of ListW
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public ListW()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public ListW(IEnumerable<T> e) : base(e)
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public ListW(int cap) : base(cap)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
/// <summary>
|
||||
/// Creates
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual bool Exists(T item) => Contains(item);
|
||||
/// <summary>
|
||||
/// Creates
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public virtual T[] GetArray() => ToArray();
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Socialvoid.SvObjects.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// ListW is a wrapper for <see cref="List{T}"/> that allows for the use
|
||||
/// of some custom methods.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public class DisplayPictureSize
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Properties Region
|
||||
/// <summary>
|
||||
/// The width of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("height")]
|
||||
public virtual int Width { get; set;}
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("height")]
|
||||
public virtual int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("document")]
|
||||
public virtual Document Document { get; set; }
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
/// Creates a new instance of ListW
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public DisplayPictureSize()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
/// <summary>
|
||||
/// Checks if this <see cref="DisplayPictureSize"/> has a
|
||||
/// valid document.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public bool HasDocument() =>
|
||||
Document != null;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Socialvoid.SvObjects.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// ListW is a wrapper for <see cref="List{T}"/> that allows for the use
|
||||
/// of some custom methods.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public class Document
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Properties Region
|
||||
/// <summary>
|
||||
/// The width of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public virtual string ID { get; set;}
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("file_mime")]
|
||||
public virtual string MimeType { get; set; }
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("file_name")]
|
||||
public virtual string FileName { get; set; }
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("file_size")]
|
||||
public virtual int FileSize { get; set; }
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("file_type")]
|
||||
public virtual string FileType { get; set; }
|
||||
/// <summary>
|
||||
/// The height of the picture.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("flags")]
|
||||
public virtual string[] Flags { get; set; }
|
||||
/// <summary>
|
||||
/// The Unix Timestamp for when this document was first created.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("created_timestamp")]
|
||||
public virtual long CreatedAt
|
||||
{
|
||||
get => _createdAt.Ticks;
|
||||
set => _createdAt = new DateTime(value);
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region field's Region
|
||||
private long _ticks;
|
||||
private DateTime _createdAt = DateTime.MinValue;
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
/// Creates a new instance of a <see cref="Document"/>.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public Document()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
/// <summary>
|
||||
/// Checks if this <see cref="DisplayPictureSize"/> has a
|
||||
/// valid document.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public bool HasID() => !string.IsNullOrEmpty(ID);
|
||||
/// <summary>
|
||||
/// converts file size to KB.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public float ConvertToKB() => FileSize / 1024f;
|
||||
/// <summary>
|
||||
/// converts file size to MB.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public float ConvertToMB() => ConvertToKB() / 1024f;
|
||||
/// <summary>
|
||||
/// converts file size to GB.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public float ConvertToGB() => ConvertToMB() / 1024f;
|
||||
/// <summary>
|
||||
/// converts file size to GB.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public System.DateTime GetTimeStamp() =>
|
||||
_createdAt != DateTime.MinValue ? _createdAt:
|
||||
new(CreatedAt);
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
|
||||
* Copyright (c) 2021 Socialvoid.NET Authors.
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code of library.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Socialvoid.SvObjects.Media;
|
||||
|
||||
namespace Socialvoid.SvObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// A peer object provides a basic description and identification
|
||||
/// of a peer entity that can contain information used to display the peer
|
||||
/// on the client or basic flags and properties of the peer to pre-determine
|
||||
/// what actions are available for a peer.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
public class Peer
|
||||
{
|
||||
//-------------------------------------------------
|
||||
#region Constant's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Properties Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Properties Region
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public string PeerID { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public string PeerType { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Username { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("display_picture_sizes")]
|
||||
public List<DisplayPictureSize> DisplayPictureSizes { get; set; }
|
||||
/// <summary>
|
||||
/// The ID of the session obtained when establishing a session.
|
||||
/// <code> since: v0.0.0 </code>
|
||||
/// </summary>
|
||||
[JsonPropertyName("flags")]
|
||||
public string[] Flags { get; set; }
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static event field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region event field's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Constructor's Region
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Peer()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Destructor's Region
|
||||
// some members here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Initialize Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Graphical Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region event Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region overrided Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region ordinary Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Get Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region Set Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
#region static Method's Region
|
||||
// some methods here
|
||||
#endregion
|
||||
//-------------------------------------------------
|
||||
}
|
||||
}
|
|
@ -37,16 +37,35 @@ namespace Tests.Client
|
|||
"4c7148caff498d24deee6c8325f1c15773d637ed76c3a4056e00b77b2beb3097", // public hash
|
||||
"866d3218b239d39c174fa2b16f54e0fa58f9c69fce8c2d941c12a47a7bc75229", // private hash
|
||||
"Linux", // platform
|
||||
"Test .NET RCP Client", // the name
|
||||
"Test .NET RPC Client", // the name
|
||||
"1.0.0.0" // version
|
||||
)]
|
||||
public void AuthenticateUserTest(string publicHash, string privateHash,
|
||||
string platform, string name, string version)
|
||||
{
|
||||
var myClient =
|
||||
var myClient =
|
||||
SocialvoidClient.GetClient(publicHash,
|
||||
privateHash, platform, name, version);
|
||||
myClient.CreateSession();
|
||||
|
||||
try
|
||||
{
|
||||
myClient.CreateSession();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NUnit.Framework.Assert.Fail("Exception thrown: " + e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
myClient.GetTermsOfService();
|
||||
var peer = myClient.Register("aliwoto", "12345678", "エイリ・ヲト");
|
||||
}
|
||||
catch (UsernameAlreadyExistsException)
|
||||
{
|
||||
Console.WriteLine("Username already exists");
|
||||
}
|
||||
myClient.AuthenticateUser("aliwoto", "12345678");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue