aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api/Controllers/QuickConnectController.cs
blob: 14f5265aa78980b51a38247d788a42ddbc165dd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Jellyfin.Api.Helpers;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Model.QuickConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Jellyfin.Api.Controllers;

/// <summary>
/// Quick connect controller.
/// </summary>
public class QuickConnectController : BaseJellyfinApiController
{
    private readonly IQuickConnect _quickConnect;
    private readonly IAuthorizationContext _authContext;

    /// <summary>
    /// Initializes a new instance of the <see cref="QuickConnectController"/> class.
    /// </summary>
    /// <param name="quickConnect">Instance of the <see cref="IQuickConnect"/> interface.</param>
    /// <param name="authContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
    public QuickConnectController(IQuickConnect quickConnect, IAuthorizationContext authContext)
    {
        _quickConnect = quickConnect;
        _authContext = authContext;
    }

    /// <summary>
    /// Gets the current quick connect state.
    /// </summary>
    /// <response code="200">Quick connect state returned.</response>
    /// <returns>Whether Quick Connect is enabled on the server or not.</returns>
    [HttpGet("Enabled")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public ActionResult<bool> GetQuickConnectEnabled()
    {
        return _quickConnect.IsEnabled;
    }

    /// <summary>
    /// Initiate a new quick connect request.
    /// </summary>
    /// <response code="200">Quick connect request successfully created.</response>
    /// <response code="401">Quick connect is not active on this server.</response>
    /// <returns>A <see cref="QuickConnectResult"/> with a secret and code for future use or an error message.</returns>
    [HttpPost("Initiate")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public async Task<ActionResult<QuickConnectResult>> InitiateQuickConnect()
    {
        try
        {
            var auth = await _authContext.GetAuthorizationInfo(Request).ConfigureAwait(false);
            return _quickConnect.TryConnect(auth);
        }
        catch (AuthenticationException)
        {
            return Unauthorized("Quick connect is disabled");
        }
    }

    /// <summary>
    /// Old version of <see cref="InitiateQuickConnect" /> using a GET method.
    /// Still available to avoid breaking compatibility.
    /// </summary>
    /// <returns>The result of <see cref="InitiateQuickConnect" />.</returns>
    [Obsolete("Use POST request instead")]
    [HttpGet("Initiate")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public Task<ActionResult<QuickConnectResult>> InitiateQuickConnectLegacy() => InitiateQuickConnect();

    /// <summary>
    /// Attempts to retrieve authentication information.
    /// </summary>
    /// <param name="secret">Secret previously returned from the Initiate endpoint.</param>
    /// <response code="200">Quick connect result returned.</response>
    /// <response code="404">Unknown quick connect secret.</response>
    /// <returns>An updated <see cref="QuickConnectResult"/>.</returns>
    [HttpGet("Connect")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public ActionResult<QuickConnectResult> GetQuickConnectState([FromQuery, Required] string secret)
    {
        try
        {
            return _quickConnect.CheckRequestStatus(secret);
        }
        catch (ResourceNotFoundException)
        {
            return NotFound("Unknown secret");
        }
        catch (AuthenticationException)
        {
            return Unauthorized("Quick connect is disabled");
        }
    }

    /// <summary>
    /// Authorizes a pending quick connect request.
    /// </summary>
    /// <param name="code">Quick connect code to authorize.</param>
    /// <param name="userId">The user the authorize. Access to the requested user is required.</param>
    /// <response code="200">Quick connect result authorized successfully.</response>
    /// <response code="403">Unknown user id.</response>
    /// <returns>Boolean indicating if the authorization was successful.</returns>
    [HttpPost("Authorize")]
    [Authorize]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<ActionResult<bool>> AuthorizeQuickConnect([FromQuery, Required] string code, [FromQuery] Guid? userId = null)
    {
        userId = RequestHelpers.GetUserId(User, userId);

        try
        {
            return await _quickConnect.AuthorizeRequest(userId.Value, code).ConfigureAwait(false);
        }
        catch (AuthenticationException)
        {
            return Unauthorized("Quick connect is disabled");
        }
    }
}