2014-10-20 03:04:45 +00:00
using MediaBrowser.Common.Configuration ;
2014-08-25 03:54:45 +00:00
using MediaBrowser.Common.Net ;
2015-03-17 05:58:29 +00:00
using MediaBrowser.Common.Security ;
2014-08-25 03:54:45 +00:00
using MediaBrowser.Controller ;
using MediaBrowser.Controller.Configuration ;
using MediaBrowser.Controller.Connect ;
2014-09-14 15:10:51 +00:00
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Library ;
2014-10-13 20:14:53 +00:00
using MediaBrowser.Controller.Providers ;
2014-08-25 03:54:45 +00:00
using MediaBrowser.Controller.Security ;
2014-09-14 23:39:06 +00:00
using MediaBrowser.Model.Connect ;
2014-10-13 20:14:53 +00:00
using MediaBrowser.Model.Entities ;
2014-08-25 03:54:45 +00:00
using MediaBrowser.Model.Logging ;
2014-09-04 01:44:40 +00:00
using MediaBrowser.Model.Net ;
2014-08-25 03:54:45 +00:00
using MediaBrowser.Model.Serialization ;
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
2014-10-12 17:31:41 +00:00
using System.Linq ;
2014-09-06 04:21:23 +00:00
using System.Net ;
2016-03-25 16:23:48 +00:00
using System.Net.Sockets ;
2014-08-25 03:54:45 +00:00
using System.Text ;
using System.Threading ;
using System.Threading.Tasks ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Model.IO ;
2016-04-10 21:11:06 +00:00
using MediaBrowser.Common.Extensions ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Common.IO ;
using MediaBrowser.Controller.IO ;
2014-08-25 03:54:45 +00:00
namespace MediaBrowser.Server.Implementations.Connect
{
public class ConnectManager : IConnectManager
{
2014-10-13 20:14:53 +00:00
private readonly SemaphoreSlim _operationLock = new SemaphoreSlim ( 1 , 1 ) ;
2014-10-12 18:12:20 +00:00
2014-08-25 03:54:45 +00:00
private readonly ILogger _logger ;
private readonly IApplicationPaths _appPaths ;
private readonly IJsonSerializer _json ;
private readonly IEncryptionManager _encryption ;
private readonly IHttpClient _httpClient ;
private readonly IServerApplicationHost _appHost ;
private readonly IServerConfigurationManager _config ;
2014-09-14 15:10:51 +00:00
private readonly IUserManager _userManager ;
2014-10-13 20:14:53 +00:00
private readonly IProviderManager _providerManager ;
2015-03-17 05:58:29 +00:00
private readonly ISecurityManager _securityManager ;
2015-09-13 23:07:54 +00:00
private readonly IFileSystem _fileSystem ;
2014-08-25 03:54:45 +00:00
2014-09-14 15:10:51 +00:00
private ConnectData _data = new ConnectData ( ) ;
public string ConnectServerId
{
get { return _data . ServerId ; }
}
public string ConnectAccessKey
{
get { return _data . AccessKey ; }
}
2014-08-25 03:54:45 +00:00
2016-03-25 16:23:48 +00:00
private IPAddress DiscoveredWanIpAddress { get ; set ; }
2014-08-25 03:54:45 +00:00
2014-09-10 00:28:59 +00:00
public string WanIpAddress
{
get
{
var address = _config . Configuration . WanDdns ;
2016-04-05 19:34:45 +00:00
if ( ! string . IsNullOrWhiteSpace ( address ) )
{
2016-07-30 03:58:15 +00:00
Uri newUri ;
if ( Uri . TryCreate ( address , UriKind . Absolute , out newUri ) )
2016-04-05 19:34:45 +00:00
{
2016-07-30 03:58:15 +00:00
address = newUri . Host ;
2016-04-05 19:34:45 +00:00
}
}
2016-03-25 16:23:48 +00:00
if ( string . IsNullOrWhiteSpace ( address ) & & DiscoveredWanIpAddress ! = null )
2014-09-10 00:28:59 +00:00
{
2016-03-25 16:23:48 +00:00
if ( DiscoveredWanIpAddress . AddressFamily = = AddressFamily . InterNetworkV6 )
{
address = "[" + DiscoveredWanIpAddress + "]" ;
}
else
{
address = DiscoveredWanIpAddress . ToString ( ) ;
}
2014-09-10 00:28:59 +00:00
}
return address ;
}
}
2014-09-14 15:10:51 +00:00
2014-08-25 03:54:45 +00:00
public string WanApiAddress
{
get
{
var ip = WanIpAddress ;
if ( ! string . IsNullOrEmpty ( ip ) )
{
if ( ! ip . StartsWith ( "http://" , StringComparison . OrdinalIgnoreCase ) & &
! ip . StartsWith ( "https://" , StringComparison . OrdinalIgnoreCase ) )
{
2015-01-19 04:29:57 +00:00
ip = ( _appHost . EnableHttps ? "https://" : "http://" ) + ip ;
2014-08-25 03:54:45 +00:00
}
2015-01-19 04:53:28 +00:00
ip + = ":" ;
ip + = _appHost . EnableHttps ? _config . Configuration . PublicHttpsPort . ToString ( CultureInfo . InvariantCulture ) : _config . Configuration . PublicPort . ToString ( CultureInfo . InvariantCulture ) ;
return ip ;
2014-08-25 03:54:45 +00:00
}
return null ;
}
}
2014-11-30 19:01:33 +00:00
private string XApplicationValue
{
2015-01-19 04:29:57 +00:00
get { return _appHost . Name + "/" + _appHost . ApplicationVersion ; }
2014-11-30 19:01:33 +00:00
}
2014-08-25 03:54:45 +00:00
public ConnectManager ( ILogger logger ,
IApplicationPaths appPaths ,
IJsonSerializer json ,
IEncryptionManager encryption ,
IHttpClient httpClient ,
IServerApplicationHost appHost ,
2015-09-13 23:07:54 +00:00
IServerConfigurationManager config , IUserManager userManager , IProviderManager providerManager , ISecurityManager securityManager , IFileSystem fileSystem )
2014-08-25 03:54:45 +00:00
{
_logger = logger ;
_appPaths = appPaths ;
_json = json ;
_encryption = encryption ;
_httpClient = httpClient ;
_appHost = appHost ;
_config = config ;
2014-09-14 15:10:51 +00:00
_userManager = userManager ;
2014-10-13 20:14:53 +00:00
_providerManager = providerManager ;
2015-03-17 05:58:29 +00:00
_securityManager = securityManager ;
2015-09-13 23:07:54 +00:00
_fileSystem = fileSystem ;
2014-08-25 03:54:45 +00:00
LoadCachedData ( ) ;
}
2016-06-30 04:23:52 +00:00
internal void Start ( )
{
_config . ConfigurationUpdated + = _config_ConfigurationUpdated ;
}
2016-03-25 16:23:48 +00:00
internal void OnWanAddressResolved ( IPAddress address )
2014-08-25 03:54:45 +00:00
{
2014-09-10 00:28:59 +00:00
DiscoveredWanIpAddress = address ;
2014-08-25 03:54:45 +00:00
2016-08-05 21:15:48 +00:00
var task = UpdateConnectInfo ( ) ;
2014-08-25 03:54:45 +00:00
}
2015-06-03 03:16:39 +00:00
private async Task UpdateConnectInfo ( )
2014-10-12 18:12:20 +00:00
{
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
try
{
await UpdateConnectInfoInternal ( ) . ConfigureAwait ( false ) ;
}
finally
{
_operationLock . Release ( ) ;
}
}
private async Task UpdateConnectInfoInternal ( )
2014-08-25 03:54:45 +00:00
{
var wanApiAddress = WanApiAddress ;
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
2015-03-21 16:10:02 +00:00
_logger . Warn ( "Cannot update Emby Connect information without a WanApiAddress" ) ;
2014-08-25 03:54:45 +00:00
return ;
}
try
{
2016-06-19 06:18:29 +00:00
var localAddress = await _appHost . GetLocalApiUrl ( ) . ConfigureAwait ( false ) ;
2014-10-23 04:26:01 +00:00
2014-08-25 03:54:45 +00:00
var hasExistingRecord = ! string . IsNullOrWhiteSpace ( ConnectServerId ) & &
! string . IsNullOrWhiteSpace ( ConnectAccessKey ) ;
2014-09-04 01:44:40 +00:00
var createNewRegistration = ! hasExistingRecord ;
2014-08-25 03:54:45 +00:00
if ( hasExistingRecord )
{
2014-09-04 01:44:40 +00:00
try
{
2014-10-23 04:26:01 +00:00
await UpdateServerRegistration ( wanApiAddress , localAddress ) . ConfigureAwait ( false ) ;
2014-09-04 01:44:40 +00:00
}
catch ( HttpException ex )
{
2015-01-19 04:29:57 +00:00
if ( ! ex . StatusCode . HasValue | | ! new [ ] { HttpStatusCode . NotFound , HttpStatusCode . Unauthorized } . Contains ( ex . StatusCode . Value ) )
2014-09-04 01:44:40 +00:00
{
throw ;
}
createNewRegistration = true ;
}
2014-08-25 03:54:45 +00:00
}
2014-09-04 01:44:40 +00:00
if ( createNewRegistration )
2014-08-25 03:54:45 +00:00
{
2014-10-23 04:26:01 +00:00
await CreateServerRegistration ( wanApiAddress , localAddress ) . ConfigureAwait ( false ) ;
2014-08-25 03:54:45 +00:00
}
2014-10-12 17:31:41 +00:00
2015-01-19 04:29:57 +00:00
_lastReportedIdentifier = GetConnectReportingIdentifier ( localAddress , wanApiAddress ) ;
2014-10-14 04:22:17 +00:00
await RefreshAuthorizationsInternal ( true , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-08-25 03:54:45 +00:00
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error registering with Connect" , ex ) ;
}
}
2014-10-13 20:14:53 +00:00
2015-01-19 04:29:57 +00:00
private string _lastReportedIdentifier ;
2016-06-19 06:18:29 +00:00
private async Task < string > GetConnectReportingIdentifier ( )
2015-01-19 04:29:57 +00:00
{
2016-06-19 06:18:29 +00:00
var url = await _appHost . GetLocalApiUrl ( ) . ConfigureAwait ( false ) ;
return GetConnectReportingIdentifier ( url , WanApiAddress ) ;
2015-01-19 04:29:57 +00:00
}
private string GetConnectReportingIdentifier ( string localAddress , string remoteAddress )
{
return ( remoteAddress ? ? string . Empty ) + ( localAddress ? ? string . Empty ) ;
}
2016-06-19 06:18:29 +00:00
async void _config_ConfigurationUpdated ( object sender , EventArgs e )
2015-01-19 04:29:57 +00:00
{
// If info hasn't changed, don't report anything
2016-06-19 06:18:29 +00:00
var connectIdentifier = await GetConnectReportingIdentifier ( ) . ConfigureAwait ( false ) ;
if ( string . Equals ( _lastReportedIdentifier , connectIdentifier , StringComparison . OrdinalIgnoreCase ) )
2015-01-19 04:29:57 +00:00
{
return ;
}
2016-06-19 06:18:29 +00:00
await UpdateConnectInfo ( ) . ConfigureAwait ( false ) ;
2015-01-19 04:29:57 +00:00
}
2014-10-23 04:26:01 +00:00
private async Task CreateServerRegistration ( string wanApiAddress , string localAddress )
2014-08-25 03:54:45 +00:00
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
throw new ArgumentNullException ( "wanApiAddress" ) ;
}
2015-02-11 03:28:34 +00:00
2014-08-25 03:54:45 +00:00
var url = "Servers" ;
url = GetConnectUrl ( url ) ;
2014-09-03 02:30:05 +00:00
var postData = new Dictionary < string , string >
{
2016-04-05 19:34:45 +00:00
{ "name" , _appHost . FriendlyName } ,
{ "url" , wanApiAddress } ,
2014-10-13 20:14:53 +00:00
{ "systemId" , _appHost . SystemId }
2014-09-03 02:30:05 +00:00
} ;
2014-08-25 03:54:45 +00:00
2014-10-23 04:26:01 +00:00
if ( ! string . IsNullOrWhiteSpace ( localAddress ) )
{
postData [ "localAddress" ] = localAddress ;
}
2014-11-30 19:01:33 +00:00
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-11-30 19:01:33 +00:00
} ;
options . SetPostData ( postData ) ;
SetApplicationHeader ( options ) ;
using ( var response = await _httpClient . Post ( options ) . ConfigureAwait ( false ) )
2014-08-25 03:54:45 +00:00
{
2014-11-30 19:01:33 +00:00
var data = _json . DeserializeFromStream < ServerRegistrationResponse > ( response . Content ) ;
2014-08-25 03:54:45 +00:00
2014-09-14 15:10:51 +00:00
_data . ServerId = data . Id ;
_data . AccessKey = data . AccessKey ;
2014-08-25 03:54:45 +00:00
CacheData ( ) ;
}
}
2014-10-23 04:26:01 +00:00
private async Task UpdateServerRegistration ( string wanApiAddress , string localAddress )
2014-08-25 03:54:45 +00:00
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
throw new ArgumentNullException ( "wanApiAddress" ) ;
}
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-02 19:44:06 +00:00
var url = "Servers" ;
2014-08-25 03:54:45 +00:00
url = GetConnectUrl ( url ) ;
2014-09-02 19:44:06 +00:00
url + = "?id=" + ConnectServerId ;
2014-08-25 03:54:45 +00:00
2014-10-23 04:26:01 +00:00
var postData = new Dictionary < string , string >
{
{ "name" , _appHost . FriendlyName } ,
{ "url" , wanApiAddress } ,
{ "systemId" , _appHost . SystemId }
} ;
if ( ! string . IsNullOrWhiteSpace ( localAddress ) )
{
postData [ "localAddress" ] = localAddress ;
}
2014-09-03 02:30:05 +00:00
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-09-03 02:30:05 +00:00
} ;
2014-10-23 04:26:01 +00:00
options . SetPostData ( postData ) ;
2014-09-03 02:30:05 +00:00
2014-09-14 15:10:51 +00:00
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-08-25 03:54:45 +00:00
// No need to examine the response
2014-09-03 02:30:05 +00:00
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
2014-08-25 03:54:45 +00:00
{
}
}
2014-10-13 20:14:53 +00:00
private readonly object _dataFileLock = new object ( ) ;
2014-08-25 03:54:45 +00:00
private string CacheFilePath
{
get { return Path . Combine ( _appPaths . DataPath , "connect.txt" ) ; }
}
private void CacheData ( )
{
var path = CacheFilePath ;
try
{
2016-03-09 17:40:29 +00:00
_fileSystem . CreateDirectory ( Path . GetDirectoryName ( path ) ) ;
2014-08-25 03:54:45 +00:00
2014-09-14 15:10:51 +00:00
var json = _json . SerializeToString ( _data ) ;
2014-08-25 03:54:45 +00:00
var encrypted = _encryption . EncryptString ( json ) ;
2014-10-13 20:14:53 +00:00
lock ( _dataFileLock )
{
2016-03-09 17:40:29 +00:00
_fileSystem . WriteAllText ( path , encrypted , Encoding . UTF8 ) ;
2014-10-13 20:14:53 +00:00
}
2014-08-25 03:54:45 +00:00
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error saving data" , ex ) ;
}
}
private void LoadCachedData ( )
{
var path = CacheFilePath ;
2016-06-30 03:34:56 +00:00
_logger . Info ( "Loading data from {0}" , path ) ;
2016-06-30 02:38:20 +00:00
2014-08-25 03:54:45 +00:00
try
{
2014-10-13 20:14:53 +00:00
lock ( _dataFileLock )
{
2016-03-09 17:40:29 +00:00
var encrypted = _fileSystem . ReadAllText ( path , Encoding . UTF8 ) ;
2014-08-25 03:54:45 +00:00
2014-10-13 20:14:53 +00:00
var json = _encryption . DecryptString ( encrypted ) ;
2014-08-25 03:54:45 +00:00
2014-10-13 20:14:53 +00:00
_data = _json . DeserializeFromString < ConnectData > ( json ) ;
}
2014-08-25 03:54:45 +00:00
}
catch ( IOException )
{
// File isn't there. no biggie
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error loading data" , ex ) ;
}
}
2014-09-14 15:10:51 +00:00
private User GetUser ( string id )
{
var user = _userManager . GetUserById ( id ) ;
if ( user = = null )
{
throw new ArgumentException ( "User not found." ) ;
}
return user ;
}
2014-08-25 03:54:45 +00:00
private string GetConnectUrl ( string handler )
{
2015-08-28 04:19:08 +00:00
return "https://connect.emby.media/service/" + handler ;
2014-08-25 03:54:45 +00:00
}
2014-09-14 15:10:51 +00:00
2014-09-14 23:39:06 +00:00
public async Task < UserLinkResult > LinkUser ( string userId , string connectUsername )
2014-10-13 20:14:53 +00:00
{
2016-09-23 06:20:56 +00:00
if ( string . IsNullOrWhiteSpace ( userId ) )
{
throw new ArgumentNullException ( "userId" ) ;
}
if ( string . IsNullOrWhiteSpace ( connectUsername ) )
{
throw new ArgumentNullException ( "connectUsername" ) ;
}
2015-06-03 15:26:39 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
await UpdateConnectInfo ( ) . ConfigureAwait ( false ) ;
}
2016-03-09 17:40:29 +00:00
2014-10-13 20:14:53 +00:00
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
try
{
return await LinkUserInternal ( userId , connectUsername ) . ConfigureAwait ( false ) ;
}
finally
{
_operationLock . Release ( ) ;
}
}
private async Task < UserLinkResult > LinkUserInternal ( string userId , string connectUsername )
2014-09-14 15:10:51 +00:00
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-14 15:10:51 +00:00
var connectUser = await GetConnectUser ( new ConnectUserQuery
{
2014-11-04 12:41:12 +00:00
NameOrEmail = connectUsername
2014-09-14 15:10:51 +00:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-09-14 17:25:46 +00:00
if ( ! connectUser . IsActive )
{
2015-03-21 16:10:02 +00:00
throw new ArgumentException ( "The Emby account has been disabled." ) ;
2014-09-14 17:25:46 +00:00
}
2016-09-23 06:20:56 +00:00
var existingUser = _userManager . Users . FirstOrDefault ( i = > string . Equals ( i . ConnectUserId , connectUser . Id ) & & ! string . IsNullOrWhiteSpace ( i . ConnectAccessKey ) ) ;
if ( existingUser ! = null )
{
throw new InvalidOperationException ( "This connect user is already linked to local user " + existingUser . Name ) ;
}
2014-09-14 15:10:51 +00:00
var user = GetUser ( userId ) ;
if ( ! string . IsNullOrWhiteSpace ( user . ConnectUserId ) )
{
2016-09-13 17:49:13 +00:00
await RemoveConnect ( user , user . ConnectUserId ) . ConfigureAwait ( false ) ;
2014-09-14 15:10:51 +00:00
}
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-09-14 15:10:51 +00:00
} ;
var accessToken = Guid . NewGuid ( ) . ToString ( "N" ) ;
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "userId" , connectUser . Id } ,
{ "userType" , "Linked" } ,
{ "accessToken" , accessToken }
} ;
options . SetPostData ( postData ) ;
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-09-14 15:10:51 +00:00
2014-09-14 23:39:06 +00:00
var result = new UserLinkResult ( ) ;
2014-09-14 15:10:51 +00:00
// No need to examine the response
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
{
2014-09-14 17:12:47 +00:00
var response = _json . DeserializeFromStream < ServerUserAuthorizationResponse > ( stream ) ;
2014-09-14 23:39:06 +00:00
result . IsPending = string . Equals ( response . AcceptStatus , "waiting" , StringComparison . OrdinalIgnoreCase ) ;
2014-09-14 15:10:51 +00:00
}
user . ConnectAccessKey = accessToken ;
user . ConnectUserName = connectUser . Name ;
user . ConnectUserId = connectUser . Id ;
2014-09-14 23:39:06 +00:00
user . ConnectLinkType = UserLinkType . LinkedUser ;
2014-09-14 15:10:51 +00:00
await user . UpdateToRepository ( ItemUpdateType . MetadataEdit , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-09-14 23:39:06 +00:00
2014-12-20 06:06:27 +00:00
await _userManager . UpdateConfiguration ( user . Id . ToString ( "N" ) , user . Configuration ) ;
2014-10-13 20:14:53 +00:00
2014-10-14 04:22:17 +00:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
2014-09-14 23:39:06 +00:00
return result ;
2014-09-14 15:10:51 +00:00
}
2014-10-14 04:22:17 +00:00
2014-10-31 04:57:24 +00:00
public async Task < UserLinkResult > InviteUser ( ConnectAuthorizationRequest request )
2014-09-14 15:10:51 +00:00
{
2015-06-03 15:26:39 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
await UpdateConnectInfo ( ) . ConfigureAwait ( false ) ;
}
2016-03-09 17:40:29 +00:00
2014-10-13 20:14:53 +00:00
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
2014-09-14 15:10:51 +00:00
2014-10-13 20:14:53 +00:00
try
{
2014-10-31 04:57:24 +00:00
return await InviteUserInternal ( request ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
}
finally
{
_operationLock . Release ( ) ;
}
2014-09-14 15:10:51 +00:00
}
2014-10-31 04:57:24 +00:00
private async Task < UserLinkResult > InviteUserInternal ( ConnectAuthorizationRequest request )
2014-09-14 15:10:51 +00:00
{
2014-10-31 04:57:24 +00:00
var connectUsername = request . ConnectUserName ;
var sendingUserId = request . SendingUserId ;
2014-10-13 20:14:53 +00:00
if ( string . IsNullOrWhiteSpace ( connectUsername ) )
2014-09-14 15:10:51 +00:00
{
2014-10-13 20:14:53 +00:00
throw new ArgumentNullException ( "connectUsername" ) ;
}
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-14 15:10:51 +00:00
2014-11-19 02:45:12 +00:00
var sendingUser = GetUser ( sendingUserId ) ;
var requesterUserName = sendingUser . ConnectUserName ;
if ( string . IsNullOrWhiteSpace ( requesterUserName ) )
{
throw new ArgumentException ( "A Connect account is required in order to send invitations." ) ;
}
2014-10-23 04:26:01 +00:00
string connectUserId = null ;
var result = new UserLinkResult ( ) ;
try
2014-10-13 20:14:53 +00:00
{
2014-10-23 04:26:01 +00:00
var connectUser = await GetConnectUser ( new ConnectUserQuery
{
2014-11-04 12:41:12 +00:00
NameOrEmail = connectUsername
2014-09-14 15:10:51 +00:00
2014-10-23 04:26:01 +00:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
2014-10-23 04:26:01 +00:00
if ( ! connectUser . IsActive )
{
2015-04-10 14:01:16 +00:00
throw new ArgumentException ( "The Emby account is not active. Please ensure the account has been activated by following the instructions within the email confirmation." ) ;
2014-10-23 04:26:01 +00:00
}
connectUserId = connectUser . Id ;
result . GuestDisplayName = connectUser . Name ;
}
catch ( HttpException ex )
2014-10-13 20:14:53 +00:00
{
2016-04-10 21:11:06 +00:00
if ( ! ex . StatusCode . HasValue )
{
throw ;
}
// If they entered a username, then whatever the error is just throw it, for example, user not found
if ( ! Validator . EmailIsValid ( connectUsername ) )
{
if ( ex . StatusCode . Value = = HttpStatusCode . NotFound )
{
throw new ResourceNotFoundException ( ) ;
}
throw ;
}
if ( ex . StatusCode . Value ! = HttpStatusCode . NotFound )
2014-10-23 04:26:01 +00:00
{
throw ;
}
}
if ( string . IsNullOrWhiteSpace ( connectUserId ) )
{
return await SendNewUserInvitation ( requesterUserName , connectUsername ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
}
2014-09-14 15:10:51 +00:00
2014-10-13 20:14:53 +00:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
2014-09-14 15:10:51 +00:00
2014-10-13 20:14:53 +00:00
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-10-13 20:14:53 +00:00
} ;
2014-09-14 17:12:47 +00:00
2014-10-13 20:14:53 +00:00
var accessToken = Guid . NewGuid ( ) . ToString ( "N" ) ;
2014-10-16 03:26:39 +00:00
2014-10-13 20:14:53 +00:00
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
2014-10-23 04:26:01 +00:00
{ "userId" , connectUserId } ,
2014-10-13 20:14:53 +00:00
{ "userType" , "Guest" } ,
{ "accessToken" , accessToken } ,
2014-10-16 03:26:39 +00:00
{ "requesterUserName" , requesterUserName }
2014-10-13 20:14:53 +00:00
} ;
2014-09-14 17:12:47 +00:00
2014-10-13 20:14:53 +00:00
options . SetPostData ( postData ) ;
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-10-13 20:14:53 +00:00
// No need to examine the response
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
{
var response = _json . DeserializeFromStream < ServerUserAuthorizationResponse > ( stream ) ;
result . IsPending = string . Equals ( response . AcceptStatus , "waiting" , StringComparison . OrdinalIgnoreCase ) ;
2014-10-31 04:57:24 +00:00
2014-11-03 03:38:43 +00:00
_data . PendingAuthorizations . Add ( new ConnectAuthorizationInternal
2014-10-31 04:57:24 +00:00
{
ConnectUserId = response . UserId ,
Id = response . Id ,
ImageUrl = response . UserImageUrl ,
UserName = response . UserName ,
2015-01-20 05:19:13 +00:00
EnabledLibraries = request . EnabledLibraries ,
2015-01-13 03:46:44 +00:00
EnabledChannels = request . EnabledChannels ,
2014-11-03 03:38:43 +00:00
EnableLiveTv = request . EnableLiveTv ,
AccessToken = accessToken
2014-10-31 04:57:24 +00:00
} ) ;
CacheData ( ) ;
2014-10-13 20:14:53 +00:00
}
2014-10-14 04:22:17 +00:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
return result ;
}
2014-10-14 04:22:17 +00:00
2014-10-23 04:26:01 +00:00
private async Task < UserLinkResult > SendNewUserInvitation ( string fromName , string email )
{
var url = GetConnectUrl ( "users/invite" ) ;
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-10-23 04:26:01 +00:00
} ;
var postData = new Dictionary < string , string >
{
{ "email" , email } ,
{ "requesterUserName" , fromName }
} ;
options . SetPostData ( postData ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-10-23 04:26:01 +00:00
// No need to examine the response
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
{
}
2014-10-27 21:45:50 +00:00
2014-10-23 04:26:01 +00:00
return new UserLinkResult
{
IsNewUserInvitation = true ,
GuestDisplayName = email
} ;
}
2014-10-14 04:22:17 +00:00
public Task RemoveConnect ( string userId )
2014-10-13 20:14:53 +00:00
{
var user = GetUser ( userId ) ;
2014-10-14 04:22:17 +00:00
return RemoveConnect ( user , user . ConnectUserId ) ;
2014-10-13 20:14:53 +00:00
}
2014-10-14 04:22:17 +00:00
private async Task RemoveConnect ( User user , string connectUserId )
2014-10-13 20:14:53 +00:00
{
if ( ! string . IsNullOrWhiteSpace ( connectUserId ) )
{
await CancelAuthorizationByConnectUserId ( connectUserId ) . ConfigureAwait ( false ) ;
2014-09-14 15:10:51 +00:00
}
2014-09-14 17:12:47 +00:00
2014-09-14 15:10:51 +00:00
user . ConnectAccessKey = null ;
user . ConnectUserName = null ;
user . ConnectUserId = null ;
2014-10-14 04:22:17 +00:00
user . ConnectLinkType = null ;
2014-09-14 15:10:51 +00:00
await user . UpdateToRepository ( ItemUpdateType . MetadataEdit , CancellationToken . None ) . ConfigureAwait ( false ) ;
}
private async Task < ConnectUser > GetConnectUser ( ConnectUserQuery query , CancellationToken cancellationToken )
{
var url = GetConnectUrl ( "user" ) ;
if ( ! string . IsNullOrWhiteSpace ( query . Id ) )
{
url = url + "?id=" + WebUtility . UrlEncode ( query . Id ) ;
}
2014-11-04 12:41:12 +00:00
else if ( ! string . IsNullOrWhiteSpace ( query . NameOrEmail ) )
{
url = url + "?nameOrEmail=" + WebUtility . UrlEncode ( query . NameOrEmail ) ;
}
2014-09-14 15:10:51 +00:00
else if ( ! string . IsNullOrWhiteSpace ( query . Name ) )
{
2014-09-22 21:56:54 +00:00
url = url + "?name=" + WebUtility . UrlEncode ( query . Name ) ;
2014-09-14 15:10:51 +00:00
}
else if ( ! string . IsNullOrWhiteSpace ( query . Email ) )
{
2014-09-22 21:56:54 +00:00
url = url + "?name=" + WebUtility . UrlEncode ( query . Email ) ;
2014-09-14 15:10:51 +00:00
}
2014-11-04 23:50:26 +00:00
else
{
throw new ArgumentException ( "Empty ConnectUserQuery supplied" ) ;
}
2014-09-14 15:10:51 +00:00
var options = new HttpRequestOptions
{
CancellationToken = cancellationToken ,
2016-10-06 18:55:01 +00:00
Url = url ,
BufferContent = false
2014-09-14 15:10:51 +00:00
} ;
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-09-14 15:10:51 +00:00
using ( var stream = await _httpClient . Get ( options ) . ConfigureAwait ( false ) )
{
var response = _json . DeserializeFromStream < GetConnectUserResponse > ( stream ) ;
return new ConnectUser
{
Email = response . Email ,
Id = response . Id ,
2014-09-14 17:25:46 +00:00
Name = response . Name ,
2014-10-14 04:22:17 +00:00
IsActive = response . IsActive ,
ImageUrl = response . ImageUrl
2014-09-14 15:10:51 +00:00
} ;
}
}
2014-11-30 19:01:33 +00:00
private void SetApplicationHeader ( HttpRequestOptions options )
{
options . RequestHeaders . Add ( "X-Application" , XApplicationValue ) ;
}
2014-09-14 15:10:51 +00:00
private void SetServerAccessToken ( HttpRequestOptions options )
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectAccessKey ) )
{
throw new ArgumentNullException ( "ConnectAccessKey" ) ;
}
2015-02-11 03:28:34 +00:00
2014-09-14 15:10:51 +00:00
options . RequestHeaders . Add ( "X-Connect-Token" , ConnectAccessKey ) ;
}
2014-10-12 17:31:41 +00:00
public async Task RefreshAuthorizations ( CancellationToken cancellationToken )
2014-10-12 18:12:20 +00:00
{
await _operationLock . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
try
{
2014-10-14 04:22:17 +00:00
await RefreshAuthorizationsInternal ( true , cancellationToken ) . ConfigureAwait ( false ) ;
2014-10-12 18:12:20 +00:00
}
finally
{
_operationLock . Release ( ) ;
}
}
2014-10-14 04:22:17 +00:00
private async Task RefreshAuthorizationsInternal ( bool refreshImages , CancellationToken cancellationToken )
2014-10-12 17:31:41 +00:00
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2015-02-11 03:28:34 +00:00
2014-10-12 17:31:41 +00:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
2014-10-13 20:14:53 +00:00
url + = "?serverId=" + ConnectServerId ;
2014-10-12 17:31:41 +00:00
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = cancellationToken ,
BufferContent = false
2014-10-12 17:31:41 +00:00
} ;
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-10-12 17:31:41 +00:00
try
{
2014-10-13 20:14:53 +00:00
using ( var stream = ( await _httpClient . SendAsync ( options , "GET" ) . ConfigureAwait ( false ) ) . Content )
2014-10-12 17:31:41 +00:00
{
var list = _json . DeserializeFromStream < List < ServerUserAuthorizationResponse > > ( stream ) ;
2014-10-14 04:22:17 +00:00
await RefreshAuthorizations ( list , refreshImages ) . ConfigureAwait ( false ) ;
2014-10-12 17:31:41 +00:00
}
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error refreshing server authorizations." , ex ) ;
}
}
2014-10-14 04:22:17 +00:00
private readonly SemaphoreSlim _connectImageSemaphore = new SemaphoreSlim ( 5 , 5 ) ;
private async Task RefreshAuthorizations ( List < ServerUserAuthorizationResponse > list , bool refreshImages )
2014-10-12 17:31:41 +00:00
{
2014-10-12 17:46:25 +00:00
var users = _userManager . Users . ToList ( ) ;
// Handle existing authorizations that were removed by the Connect server
// Handle existing authorizations whose status may have been updated
foreach ( var user in users )
{
if ( ! string . IsNullOrWhiteSpace ( user . ConnectUserId ) )
{
var connectEntry = list . FirstOrDefault ( i = > string . Equals ( i . UserId , user . ConnectUserId , StringComparison . OrdinalIgnoreCase ) ) ;
if ( connectEntry = = null )
{
2014-10-23 04:26:01 +00:00
var deleteUser = user . ConnectLinkType . HasValue & &
user . ConnectLinkType . Value = = UserLinkType . Guest ;
2014-10-12 17:46:25 +00:00
user . ConnectUserId = null ;
user . ConnectAccessKey = null ;
user . ConnectUserName = null ;
2014-10-14 04:22:17 +00:00
user . ConnectLinkType = null ;
2014-10-12 17:46:25 +00:00
2014-10-12 18:12:20 +00:00
await _userManager . UpdateUser ( user ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
2014-10-23 04:26:01 +00:00
if ( deleteUser )
2014-10-12 17:52:43 +00:00
{
2014-10-13 20:14:53 +00:00
_logger . Debug ( "Deleting guest user {0}" , user . Name ) ;
2014-10-14 04:22:17 +00:00
await _userManager . DeleteUser ( user ) . ConfigureAwait ( false ) ;
2014-10-12 17:52:43 +00:00
}
2014-10-12 17:46:25 +00:00
}
else
{
var changed = ! string . Equals ( user . ConnectAccessKey , connectEntry . AccessToken , StringComparison . OrdinalIgnoreCase ) ;
if ( changed )
{
user . ConnectUserId = connectEntry . UserId ;
user . ConnectAccessKey = connectEntry . AccessToken ;
2014-10-12 17:52:43 +00:00
await _userManager . UpdateUser ( user ) . ConfigureAwait ( false ) ;
2014-10-12 17:46:25 +00:00
}
}
}
}
2014-10-31 04:57:24 +00:00
var currentPendingList = _data . PendingAuthorizations . ToList ( ) ;
2014-11-03 03:38:43 +00:00
var newPendingList = new List < ConnectAuthorizationInternal > ( ) ;
2014-10-13 20:14:53 +00:00
2014-10-12 17:52:43 +00:00
foreach ( var connectEntry in list )
{
2014-10-13 20:14:53 +00:00
if ( string . Equals ( connectEntry . UserType , "guest" , StringComparison . OrdinalIgnoreCase ) )
{
2014-10-31 04:57:24 +00:00
var currentPendingEntry = currentPendingList . FirstOrDefault ( i = > string . Equals ( i . Id , connectEntry . Id , StringComparison . OrdinalIgnoreCase ) ) ;
2014-10-13 20:14:53 +00:00
if ( string . Equals ( connectEntry . AcceptStatus , "accepted" , StringComparison . OrdinalIgnoreCase ) )
{
2014-10-16 03:26:39 +00:00
var user = _userManager . Users
. FirstOrDefault ( i = > string . Equals ( i . ConnectUserId , connectEntry . UserId , StringComparison . OrdinalIgnoreCase ) ) ;
2014-10-13 20:14:53 +00:00
if ( user = = null )
{
// Add user
2014-12-23 03:58:14 +00:00
user = await _userManager . CreateUser ( _userManager . MakeValidUsername ( connectEntry . UserName ) ) . ConfigureAwait ( false ) ;
2014-10-14 04:22:17 +00:00
user . ConnectUserName = connectEntry . UserName ;
user . ConnectUserId = connectEntry . UserId ;
user . ConnectLinkType = UserLinkType . Guest ;
user . ConnectAccessKey = connectEntry . AccessToken ;
await _userManager . UpdateUser ( user ) . ConfigureAwait ( false ) ;
2014-12-20 06:06:27 +00:00
user . Policy . IsHidden = true ;
user . Policy . EnableLiveTvManagement = false ;
user . Policy . EnableContentDeletion = false ;
user . Policy . EnableRemoteControlOfOtherUsers = false ;
user . Policy . EnableSharedDeviceControl = false ;
user . Policy . IsAdministrator = false ;
2014-10-14 04:22:17 +00:00
2014-10-31 04:57:24 +00:00
if ( currentPendingEntry ! = null )
{
2015-01-20 05:19:13 +00:00
user . Policy . EnabledFolders = currentPendingEntry . EnabledLibraries ;
user . Policy . EnableAllFolders = false ;
2015-01-13 03:46:44 +00:00
user . Policy . EnabledChannels = currentPendingEntry . EnabledChannels ;
user . Policy . EnableAllChannels = false ;
2015-01-20 05:19:13 +00:00
user . Policy . EnableLiveTvAccess = currentPendingEntry . EnableLiveTv ;
2014-10-31 04:57:24 +00:00
}
2014-12-20 06:06:27 +00:00
await _userManager . UpdateConfiguration ( user . Id . ToString ( "N" ) , user . Configuration ) ;
2014-10-13 20:14:53 +00:00
}
}
else if ( string . Equals ( connectEntry . AcceptStatus , "waiting" , StringComparison . OrdinalIgnoreCase ) )
{
2014-11-03 03:38:43 +00:00
currentPendingEntry = currentPendingEntry ? ? new ConnectAuthorizationInternal ( ) ;
2014-10-31 04:57:24 +00:00
currentPendingEntry . ConnectUserId = connectEntry . UserId ;
currentPendingEntry . ImageUrl = connectEntry . UserImageUrl ;
currentPendingEntry . UserName = connectEntry . UserName ;
currentPendingEntry . Id = connectEntry . Id ;
2014-11-03 03:38:43 +00:00
currentPendingEntry . AccessToken = connectEntry . AccessToken ;
2014-10-31 04:57:24 +00:00
newPendingList . Add ( currentPendingEntry ) ;
2014-10-13 20:14:53 +00:00
}
}
}
2014-10-31 04:57:24 +00:00
_data . PendingAuthorizations = newPendingList ;
2014-10-13 20:14:53 +00:00
CacheData ( ) ;
2014-10-14 04:22:17 +00:00
await RefreshGuestNames ( list , refreshImages ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
}
2014-10-14 04:22:17 +00:00
private async Task RefreshGuestNames ( List < ServerUserAuthorizationResponse > list , bool refreshImages )
2014-10-13 20:14:53 +00:00
{
var users = _userManager . Users
2016-03-27 21:11:27 +00:00
. Where ( i = > ! string . IsNullOrEmpty ( i . ConnectUserId ) & & i . ConnectLinkType . HasValue & & i . ConnectLinkType . Value = = UserLinkType . Guest )
2014-10-14 04:22:17 +00:00
. ToList ( ) ;
2014-10-13 20:14:53 +00:00
foreach ( var user in users )
{
2014-10-14 04:22:17 +00:00
var authorization = list . FirstOrDefault ( i = > string . Equals ( i . UserId , user . ConnectUserId , StringComparison . Ordinal ) ) ;
2014-10-13 20:14:53 +00:00
2014-10-14 04:22:17 +00:00
if ( authorization = = null )
2014-10-12 17:52:43 +00:00
{
2014-10-14 04:22:17 +00:00
_logger . Warn ( "Unable to find connect authorization record for user {0}" , user . Name ) ;
continue ;
}
2014-10-13 20:14:53 +00:00
2014-12-20 06:06:27 +00:00
var syncConnectName = true ;
var syncConnectImage = true ;
if ( syncConnectName )
2014-10-13 20:14:53 +00:00
{
2014-10-14 04:22:17 +00:00
var changed = ! string . Equals ( authorization . UserName , user . Name , StringComparison . OrdinalIgnoreCase ) ;
2014-10-13 20:14:53 +00:00
if ( changed )
2014-10-12 17:52:43 +00:00
{
2014-10-14 04:22:17 +00:00
await user . Rename ( authorization . UserName ) . ConfigureAwait ( false ) ;
2014-10-12 17:52:43 +00:00
}
}
2014-10-13 20:14:53 +00:00
2014-12-20 06:06:27 +00:00
if ( syncConnectImage )
2014-10-13 20:14:53 +00:00
{
2014-10-14 04:22:17 +00:00
var imageUrl = authorization . UserImageUrl ;
2014-10-13 20:14:53 +00:00
if ( ! string . IsNullOrWhiteSpace ( imageUrl ) )
{
var changed = false ;
if ( ! user . HasImage ( ImageType . Primary ) )
{
changed = true ;
}
2014-10-14 04:22:17 +00:00
else if ( refreshImages )
2014-10-13 20:14:53 +00:00
{
using ( var response = await _httpClient . SendAsync ( new HttpRequestOptions
{
Url = imageUrl ,
BufferContent = false
} , "HEAD" ) . ConfigureAwait ( false ) )
{
var length = response . ContentLength ;
2015-10-15 02:55:19 +00:00
if ( length ! = _fileSystem . GetFileInfo ( user . GetImageInfo ( ImageType . Primary , 0 ) . Path ) . Length )
2014-10-13 20:14:53 +00:00
{
changed = true ;
}
}
}
if ( changed )
{
2014-10-14 04:22:17 +00:00
await _providerManager . SaveImage ( user , imageUrl , _connectImageSemaphore , ImageType . Primary , null , CancellationToken . None ) . ConfigureAwait ( false ) ;
2015-09-13 23:07:54 +00:00
await user . RefreshMetadata ( new MetadataRefreshOptions ( _fileSystem )
2014-10-13 20:14:53 +00:00
{
ForceSave = true ,
2014-10-14 04:22:17 +00:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
}
}
}
}
}
public async Task < List < ConnectAuthorization > > GetPendingGuests ( )
{
2014-10-14 04:22:17 +00:00
var time = DateTime . UtcNow - _data . LastAuthorizationsRefresh ;
if ( time . TotalMinutes > = 5 )
{
await _operationLock . WaitAsync ( CancellationToken . None ) . ConfigureAwait ( false ) ;
try
{
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
_data . LastAuthorizationsRefresh = DateTime . UtcNow ;
CacheData ( ) ;
}
2015-02-11 03:28:34 +00:00
catch ( Exception ex )
{
_logger . ErrorException ( "Error refreshing authorization" , ex ) ;
}
2014-10-14 04:22:17 +00:00
finally
{
_operationLock . Release ( ) ;
}
}
2014-11-03 03:38:43 +00:00
return _data . PendingAuthorizations . Select ( i = > new ConnectAuthorization
{
ConnectUserId = i . ConnectUserId ,
EnableLiveTv = i . EnableLiveTv ,
2015-01-13 03:46:44 +00:00
EnabledChannels = i . EnabledChannels ,
2015-01-20 05:19:13 +00:00
EnabledLibraries = i . EnabledLibraries ,
2014-11-03 03:38:43 +00:00
Id = i . Id ,
ImageUrl = i . ImageUrl ,
UserName = i . UserName
} ) . ToList ( ) ;
2014-10-13 20:14:53 +00:00
}
public async Task CancelAuthorization ( string id )
{
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
try
{
await CancelAuthorizationInternal ( id ) . ConfigureAwait ( false ) ;
}
finally
{
_operationLock . Release ( ) ;
}
}
private async Task CancelAuthorizationInternal ( string id )
{
var connectUserId = _data . PendingAuthorizations
. First ( i = > string . Equals ( i . Id , id , StringComparison . Ordinal ) )
. ConnectUserId ;
await CancelAuthorizationByConnectUserId ( connectUserId ) . ConfigureAwait ( false ) ;
2014-10-14 04:22:17 +00:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 20:14:53 +00:00
}
private async Task CancelAuthorizationByConnectUserId ( string connectUserId )
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( connectUserId ) )
{
throw new ArgumentNullException ( "connectUserId" ) ;
}
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2015-02-11 03:28:34 +00:00
2014-10-13 20:14:53 +00:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
var options = new HttpRequestOptions
{
Url = url ,
2016-10-06 18:55:01 +00:00
CancellationToken = CancellationToken . None ,
BufferContent = false
2014-10-13 20:14:53 +00:00
} ;
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "userId" , connectUserId }
} ;
options . SetPostData ( postData ) ;
SetServerAccessToken ( options ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2014-10-13 20:14:53 +00:00
try
{
// No need to examine the response
using ( var stream = ( await _httpClient . SendAsync ( options , "DELETE" ) . ConfigureAwait ( false ) ) . Content )
{
}
}
catch ( HttpException ex )
{
// If connect says the auth doesn't exist, we can handle that gracefully since this is a remove operation
if ( ! ex . StatusCode . HasValue | | ex . StatusCode . Value ! = HttpStatusCode . NotFound )
{
throw ;
}
_logger . Debug ( "Connect returned a 404 when removing a user auth link. Handling it." ) ;
2014-10-12 17:52:43 +00:00
}
2014-10-12 17:31:41 +00:00
}
2014-10-17 04:52:41 +00:00
public async Task Authenticate ( string username , string passwordMd5 )
{
2014-11-04 23:50:26 +00:00
if ( string . IsNullOrWhiteSpace ( username ) )
{
throw new ArgumentNullException ( "username" ) ;
}
if ( string . IsNullOrWhiteSpace ( passwordMd5 ) )
{
throw new ArgumentNullException ( "passwordMd5" ) ;
}
2014-11-30 19:01:33 +00:00
var options = new HttpRequestOptions
2014-10-17 04:52:41 +00:00
{
2016-10-06 18:55:01 +00:00
Url = GetConnectUrl ( "user/authenticate" ) ,
BufferContent = false
2014-10-17 04:52:41 +00:00
} ;
2014-11-30 19:01:33 +00:00
options . SetPostData ( new Dictionary < string , string >
2014-10-17 04:52:41 +00:00
{
{ "userName" , username } ,
{ "password" , passwordMd5 }
} ) ;
2014-11-30 19:01:33 +00:00
SetApplicationHeader ( options ) ;
2015-02-11 03:28:34 +00:00
2014-10-17 04:52:41 +00:00
// No need to examine the response
2014-11-30 19:01:33 +00:00
using ( var response = ( await _httpClient . SendAsync ( options , "POST" ) . ConfigureAwait ( false ) ) . Content )
2014-10-17 04:52:41 +00:00
{
}
}
2014-10-27 03:06:01 +00:00
2014-11-03 03:38:43 +00:00
public async Task < User > GetLocalUser ( string connectUserId )
{
var user = _userManager . Users
. FirstOrDefault ( i = > string . Equals ( i . ConnectUserId , connectUserId , StringComparison . OrdinalIgnoreCase ) ) ;
if ( user = = null )
{
await RefreshAuthorizations ( CancellationToken . None ) . ConfigureAwait ( false ) ;
}
return _userManager . Users
. FirstOrDefault ( i = > string . Equals ( i . ConnectUserId , connectUserId , StringComparison . OrdinalIgnoreCase ) ) ;
}
2015-04-04 00:41:16 +00:00
public User GetUserFromExchangeToken ( string token )
{
if ( string . IsNullOrWhiteSpace ( token ) )
{
throw new ArgumentNullException ( "token" ) ;
}
return _userManager . Users . FirstOrDefault ( u = > string . Equals ( token , u . ConnectAccessKey , StringComparison . OrdinalIgnoreCase ) ) ;
}
2014-11-03 03:38:43 +00:00
public bool IsAuthorizationTokenValid ( string token )
{
if ( string . IsNullOrWhiteSpace ( token ) )
{
throw new ArgumentNullException ( "token" ) ;
}
return _userManager . Users . Any ( u = > string . Equals ( token , u . ConnectAccessKey , StringComparison . OrdinalIgnoreCase ) ) | |
_data . PendingAuthorizations . Select ( i = > i . AccessToken ) . Contains ( token , StringComparer . OrdinalIgnoreCase ) ;
}
2014-08-25 03:54:45 +00:00
}
}