mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Add more robot tests
This commit is contained in:
parent
14d23af0fd
commit
d257901c64
@ -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 />
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@
|
||||
"newUser": ["overall.read", "overall.write"]
|
||||
},
|
||||
"profilePicturePath": "users/",
|
||||
"secret": "jwt-secret"
|
||||
"secret": "4c@mraGB!KRfF@kpS8740y9FcHemKxBsqqxLbdR?"
|
||||
},
|
||||
|
||||
"tvdb": {
|
||||
|
@ -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
|
83
tests/robot/auth/auth.robot
Normal file
83
tests/robot/auth/auth.robot
Normal 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
|
||||
|
4
tests/robot/pyproject.toml
Normal file
4
tests/robot/pyproject.toml
Normal file
@ -0,0 +1,4 @@
|
||||
[tool.robotidy]
|
||||
configure = [
|
||||
"MergeAndOrderSections:order=comments,settings,keywords,variables,testcases"
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user