Add more robot tests

This commit is contained in:
Zoe Roux 2022-05-08 23:14:08 +02:00
parent 14d23af0fd
commit d257901c64
No known key found for this signature in database
GPG Key ID: 54F19BB73170955D
10 changed files with 163 additions and 34 deletions

View File

@ -45,6 +45,7 @@ namespace Kyoo.Abstractions.Models
/// <summary>
/// The user password (hashed, it can't be read like that). The hashing format is implementation defined.
/// </summary>
[SerializeIgnore]
public string Password { get; set; }
/// <summary>
@ -55,6 +56,7 @@ namespace Kyoo.Abstractions.Models
/// <summary>
/// Arbitrary extra data that can be used by specific authentication implementations.
/// </summary>
[SerializeIgnore]
public Dictionary<string, string> ExtraData { get; set; }
/// <inheritdoc />

View File

@ -96,7 +96,10 @@ namespace Kyoo.Authentication
/// <param name="kind">The kind of permission needed.</param>
/// <param name="group">The group of the permission.</param>
/// <param name="options">The option containing default values.</param>
public PermissionValidatorFilter(string permission, Kind kind, Group group,
public PermissionValidatorFilter(
string permission,
Kind kind,
Group group,
IOptionsMonitor<PermissionOption> options)
{
_permission = permission;

View File

@ -62,9 +62,6 @@ namespace Kyoo.Authentication
/// <inheritdoc />
public string CreateAccessToken(User user, out TimeSpan expireIn)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
expireIn = new TimeSpan(1, 0, 0);
SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(_options.Value.Secret));
@ -94,9 +91,6 @@ namespace Kyoo.Authentication
/// <inheritdoc />
public Task<string> CreateRefreshToken(User user)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(_options.Value.Secret));
SigningCredentials credential = new(key, SecurityAlgorithms.HmacSha256Signature);
JwtSecurityToken token = new(

View File

@ -31,7 +31,7 @@ namespace Kyoo.Authentication.Models
/// <summary>
/// The default jwt secret.
/// </summary>
public const string DefaultSecret = "jwt-secret";
public const string DefaultSecret = "4c@mraGB!KRfF@kpS8739y9FcHemKxBsqqxLbdR?";
/// <summary>
/// The secret used to encrypt the jwt.

View File

@ -175,15 +175,76 @@ namespace Kyoo.Authentication.Views
/// <returns>The currently authenticated user.</returns>
/// <response code="403">The given access token is invalid.</response>
[HttpGet("me")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<User>> GetMe()
{
if (!int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier), out int userID))
return Forbid();
return await _users.Get(userID);
try
{
return await _users.Get(userID);
}
catch (ItemNotFoundException)
{
return Forbid();
}
}
// TODO: Add a put to edit the current user.
/// <summary>
/// Edit self
/// </summary>
/// <remarks>
/// Edit information about the currently authenticated user.
/// </remarks>
/// <param name="user">The new data for the current user.</param>
/// <param name="resetOld">
/// Should old properties of the resource be discarded or should null values considered as not changed?
/// </param>
/// <returns>The currently authenticated user after modifications.</returns>
/// <response code="403">The given access token is invalid.</response>
[HttpPut("me")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<User>> EditMe(User user, [FromQuery] bool resetOld = true)
{
if (!int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier), out int userID))
return Forbid();
try
{
user.ID = userID;
return await _users.Edit(user, resetOld);
}
catch (ItemNotFoundException)
{
return Forbid();
}
}
/// <summary>
/// Delete account
/// </summary>
/// <remarks>
/// Delete the current account.
/// </remarks>
/// <returns>The currently authenticated user after modifications.</returns>
/// <response code="403">The given access token is invalid.</response>
[HttpDelete("me")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<User>> DeleteMe()
{
if (!int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier), out int userID))
return Forbid();
try
{
await _users.Delete(userID);
return NoContent();
}
catch (ItemNotFoundException)
{
return Forbid();
}
}
}
}

View File

@ -220,7 +220,7 @@ namespace Kyoo.Core.Api
/// <response code="404">No item could be found with the given id or slug.</response>
[HttpDelete("{identifier:id}")]
[PartialPermission(Kind.Delete)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Identifier identifier)
{
@ -236,7 +236,7 @@ namespace Kyoo.Core.Api
return NotFound();
}
return Ok();
return NoContent();
}
/// <summary>
@ -250,7 +250,7 @@ namespace Kyoo.Core.Api
/// <response code="400">One or multiple filters are invalid.</response>
[HttpDelete]
[PartialPermission(Kind.Delete)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
public async Task<IActionResult> Delete([FromQuery] Dictionary<string, string> where)
{
@ -263,7 +263,7 @@ namespace Kyoo.Core.Api
return BadRequest(new RequestError(ex.Message));
}
return Ok();
return NoContent();
}
}
}

View File

@ -65,7 +65,7 @@
"newUser": ["overall.read", "overall.write"]
},
"profilePicturePath": "users/",
"secret": "jwt-secret"
"secret": "4c@mraGB!KRfF@kpS8740y9FcHemKxBsqqxLbdR?"
},
"tvdb": {

View File

@ -1,18 +0,0 @@
*** Settings ***
Documentation Tests of the /auth route.
... Ensures that the user can authenticate on kyoo.
Resource ../rest.resource
*** Test Cases ***
BadAccount
[Documentation] Login fails if user does not exist
POST /auth/login {"username": "toto", "password": "tata"}
Output
Integer response status 403
Register
[Documentation] Create a new user and login in it
POST /auth/register {"username": "toto", "password": "tata", "email": "mail@kyoo.moe"}
Output
Integer response status 403

View File

@ -0,0 +1,83 @@
*** Settings ***
Documentation Tests of the /auth route.
... Ensures that the user can authenticate on kyoo.
Resource ../rest.resource
*** Keywords ***
Login
[Documentation] Shortcut to login with the given username for future requests
[Arguments] ${username}
&{res}= POST /auth/login {"username": "${username}", "password": "password-${username}"}
Output
Integer response status 200
String response body access_token
Set Headers {"Authorization": "Bearer ${res.body.access_token}"}
Register
[Documentation] Shortcut to register with the given username for future requests
[Arguments] ${username}
&{res}= POST
... /auth/register
... {"username": "${username}", "password": "password-${username}", "email": "${username}@kyoo.moe"}
Output
Integer response status 200
String response body access_token
Set Headers {"Authorization": "Bearer ${res.body.access_token}"}
Logout
[Documentation] Logout the current user, only the local client is affected.
Set Headers {"Authorization": ""}
*** Test Cases ***
Me cant be accessed without an account
Get /auth/me
Output
Integer response status 403
Bad Account
[Documentation] Login fails if user does not exist
POST /auth/login {"username": "i-don-t-exist", "password": "pass"}
Output
Integer response status 403
Register
[Documentation] Create a new user and login in it
Register user-1
[Teardown] DELETE /auth/me
Register Duplicates
[Documentation] If two users tries to register with the same username, it fails
Register user-duplicate
# We can't use the `Register` keyword because it assert for success
POST /auth/register {"username": "user-duplicate", "password": "pass", "email": "mail@kyoo.moe"}
Output
Integer response status 409
[Teardown] DELETE /auth/me
Delete Account
[Documentation] Check if a user can delete it's account
Register I-should-be-deleted
DELETE /auth/me
Output
Integer response status 204
Login
[Documentation] Create a new user and login in it
Register login-user
${res}= GET /auth/me
Output
Integer response status 200
String response body username login-user
Logout
Login login-user
${me}= Get /auth/me
Output
Output ${me}
Should Be Equal As Strings ${res["body"]} ${me["body"]}
[Teardown] DELETE /auth/me

View File

@ -0,0 +1,4 @@
[tool.robotidy]
configure = [
"MergeAndOrderSections:order=comments,settings,keywords,variables,testcases"
]