2014-10-20 05:04:45 +02:00
using MediaBrowser.Common.Configuration ;
2014-08-25 05:54:45 +02:00
using MediaBrowser.Common.Net ;
2015-03-17 06:58:29 +01:00
using MediaBrowser.Common.Security ;
2014-08-25 05:54:45 +02:00
using MediaBrowser.Controller ;
using MediaBrowser.Controller.Configuration ;
using MediaBrowser.Controller.Connect ;
2014-09-14 17:10:51 +02:00
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Library ;
2014-10-13 22:14:53 +02:00
using MediaBrowser.Controller.Providers ;
2014-08-25 05:54:45 +02:00
using MediaBrowser.Controller.Security ;
2014-09-15 01:39:06 +02:00
using MediaBrowser.Model.Connect ;
2014-10-13 22:14:53 +02:00
using MediaBrowser.Model.Entities ;
2014-10-27 04:06:01 +01:00
using MediaBrowser.Model.Events ;
2014-08-25 05:54:45 +02:00
using MediaBrowser.Model.Logging ;
2014-09-04 03:44:40 +02:00
using MediaBrowser.Model.Net ;
2014-08-25 05:54:45 +02:00
using MediaBrowser.Model.Serialization ;
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
2014-10-12 19:31:41 +02:00
using System.Linq ;
2014-09-06 06:21:23 +02:00
using System.Net ;
2014-08-25 05:54:45 +02:00
using System.Text ;
using System.Threading ;
using System.Threading.Tasks ;
2015-09-14 01:07:54 +02:00
using MediaBrowser.Common.IO ;
2014-08-25 05:54:45 +02:00
namespace MediaBrowser.Server.Implementations.Connect
{
public class ConnectManager : IConnectManager
{
2014-10-13 22:14:53 +02:00
private readonly SemaphoreSlim _operationLock = new SemaphoreSlim ( 1 , 1 ) ;
2014-10-12 20:12:20 +02:00
2014-08-25 05:54:45 +02: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 17:10:51 +02:00
private readonly IUserManager _userManager ;
2014-10-13 22:14:53 +02:00
private readonly IProviderManager _providerManager ;
2015-03-17 06:58:29 +01:00
private readonly ISecurityManager _securityManager ;
2015-09-14 01:07:54 +02:00
private readonly IFileSystem _fileSystem ;
2014-08-25 05:54:45 +02:00
2014-09-14 17:10:51 +02:00
private ConnectData _data = new ConnectData ( ) ;
public string ConnectServerId
{
get { return _data . ServerId ; }
}
public string ConnectAccessKey
{
get { return _data . AccessKey ; }
}
2014-08-25 05:54:45 +02:00
2014-09-10 02:28:59 +02:00
public string DiscoveredWanIpAddress { get ; private set ; }
2014-08-25 05:54:45 +02:00
2014-09-10 02:28:59 +02:00
public string WanIpAddress
{
get
{
var address = _config . Configuration . WanDdns ;
if ( string . IsNullOrWhiteSpace ( address ) )
{
address = DiscoveredWanIpAddress ;
}
return address ;
}
}
2014-09-14 17:10:51 +02:00
2014-08-25 05:54:45 +02: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 05:29:57 +01:00
ip = ( _appHost . EnableHttps ? "https://" : "http://" ) + ip ;
2014-08-25 05:54:45 +02:00
}
2015-01-19 05:53:28 +01:00
ip + = ":" ;
ip + = _appHost . EnableHttps ? _config . Configuration . PublicHttpsPort . ToString ( CultureInfo . InvariantCulture ) : _config . Configuration . PublicPort . ToString ( CultureInfo . InvariantCulture ) ;
return ip ;
2014-08-25 05:54:45 +02:00
}
return null ;
}
}
2014-11-30 20:01:33 +01:00
private string XApplicationValue
{
2015-01-19 05:29:57 +01:00
get { return _appHost . Name + "/" + _appHost . ApplicationVersion ; }
2014-11-30 20:01:33 +01:00
}
2014-08-25 05:54:45 +02:00
public ConnectManager ( ILogger logger ,
IApplicationPaths appPaths ,
IJsonSerializer json ,
IEncryptionManager encryption ,
IHttpClient httpClient ,
IServerApplicationHost appHost ,
2015-09-14 01:07:54 +02:00
IServerConfigurationManager config , IUserManager userManager , IProviderManager providerManager , ISecurityManager securityManager , IFileSystem fileSystem )
2014-08-25 05:54:45 +02:00
{
_logger = logger ;
_appPaths = appPaths ;
_json = json ;
_encryption = encryption ;
_httpClient = httpClient ;
_appHost = appHost ;
_config = config ;
2014-09-14 17:10:51 +02:00
_userManager = userManager ;
2014-10-13 22:14:53 +02:00
_providerManager = providerManager ;
2015-03-17 06:58:29 +01:00
_securityManager = securityManager ;
2015-09-14 01:07:54 +02:00
_fileSystem = fileSystem ;
2014-08-25 05:54:45 +02:00
2014-10-27 04:06:01 +01:00
_userManager . UserConfigurationUpdated + = _userManager_UserConfigurationUpdated ;
2015-01-19 05:29:57 +01:00
_config . ConfigurationUpdated + = _config_ConfigurationUpdated ;
2014-10-27 04:06:01 +01:00
2014-08-25 05:54:45 +02:00
LoadCachedData ( ) ;
}
internal void OnWanAddressResolved ( string address )
{
2014-09-10 02:28:59 +02:00
DiscoveredWanIpAddress = address ;
2014-08-25 05:54:45 +02:00
2014-09-13 16:10:30 +02:00
UpdateConnectInfo ( ) ;
2014-08-25 05:54:45 +02:00
}
2015-06-03 05:16:39 +02:00
private async Task UpdateConnectInfo ( )
2014-10-12 20:12:20 +02:00
{
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
try
{
await UpdateConnectInfoInternal ( ) . ConfigureAwait ( false ) ;
}
finally
{
_operationLock . Release ( ) ;
}
}
private async Task UpdateConnectInfoInternal ( )
2014-08-25 05:54:45 +02:00
{
var wanApiAddress = WanApiAddress ;
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
2015-03-21 17:10:02 +01:00
_logger . Warn ( "Cannot update Emby Connect information without a WanApiAddress" ) ;
2014-08-25 05:54:45 +02:00
return ;
}
try
{
2015-01-24 20:03:55 +01:00
var localAddress = _appHost . LocalApiUrl ;
2014-10-23 06:26:01 +02:00
2014-08-25 05:54:45 +02:00
var hasExistingRecord = ! string . IsNullOrWhiteSpace ( ConnectServerId ) & &
! string . IsNullOrWhiteSpace ( ConnectAccessKey ) ;
2014-09-04 03:44:40 +02:00
var createNewRegistration = ! hasExistingRecord ;
2014-08-25 05:54:45 +02:00
if ( hasExistingRecord )
{
2014-09-04 03:44:40 +02:00
try
{
2014-10-23 06:26:01 +02:00
await UpdateServerRegistration ( wanApiAddress , localAddress ) . ConfigureAwait ( false ) ;
2014-09-04 03:44:40 +02:00
}
catch ( HttpException ex )
{
2015-01-19 05:29:57 +01:00
if ( ! ex . StatusCode . HasValue | | ! new [ ] { HttpStatusCode . NotFound , HttpStatusCode . Unauthorized } . Contains ( ex . StatusCode . Value ) )
2014-09-04 03:44:40 +02:00
{
throw ;
}
createNewRegistration = true ;
}
2014-08-25 05:54:45 +02:00
}
2014-09-04 03:44:40 +02:00
if ( createNewRegistration )
2014-08-25 05:54:45 +02:00
{
2014-10-23 06:26:01 +02:00
await CreateServerRegistration ( wanApiAddress , localAddress ) . ConfigureAwait ( false ) ;
2014-08-25 05:54:45 +02:00
}
2014-10-12 19:31:41 +02:00
2015-01-19 05:29:57 +01:00
_lastReportedIdentifier = GetConnectReportingIdentifier ( localAddress , wanApiAddress ) ;
2014-10-14 06:22:17 +02:00
await RefreshAuthorizationsInternal ( true , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-08-25 05:54:45 +02:00
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error registering with Connect" , ex ) ;
}
}
2014-10-13 22:14:53 +02:00
2015-01-19 05:29:57 +01:00
private string _lastReportedIdentifier ;
private string GetConnectReportingIdentifier ( )
{
2015-01-24 20:03:55 +01:00
return GetConnectReportingIdentifier ( _appHost . LocalApiUrl , WanApiAddress ) ;
2015-01-19 05:29:57 +01:00
}
private string GetConnectReportingIdentifier ( string localAddress , string remoteAddress )
{
return ( remoteAddress ? ? string . Empty ) + ( localAddress ? ? string . Empty ) ;
}
void _config_ConfigurationUpdated ( object sender , EventArgs e )
{
// If info hasn't changed, don't report anything
if ( string . Equals ( _lastReportedIdentifier , GetConnectReportingIdentifier ( ) , StringComparison . OrdinalIgnoreCase ) )
{
return ;
}
UpdateConnectInfo ( ) ;
}
2014-10-23 06:26:01 +02:00
private async Task CreateServerRegistration ( string wanApiAddress , string localAddress )
2014-08-25 05:54:45 +02:00
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
throw new ArgumentNullException ( "wanApiAddress" ) ;
}
2015-02-11 04:28:34 +01:00
2014-08-25 05:54:45 +02:00
var url = "Servers" ;
url = GetConnectUrl ( url ) ;
2014-09-03 04:30:05 +02:00
var postData = new Dictionary < string , string >
{
{ "name" , _appHost . FriendlyName } ,
2014-09-09 03:15:31 +02:00
{ "url" , wanApiAddress } ,
2014-10-13 22:14:53 +02:00
{ "systemId" , _appHost . SystemId }
2014-09-03 04:30:05 +02:00
} ;
2014-08-25 05:54:45 +02:00
2014-10-23 06:26:01 +02:00
if ( ! string . IsNullOrWhiteSpace ( localAddress ) )
{
postData [ "localAddress" ] = localAddress ;
}
2014-11-30 20:01:33 +01:00
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
options . SetPostData ( postData ) ;
SetApplicationHeader ( options ) ;
using ( var response = await _httpClient . Post ( options ) . ConfigureAwait ( false ) )
2014-08-25 05:54:45 +02:00
{
2014-11-30 20:01:33 +01:00
var data = _json . DeserializeFromStream < ServerRegistrationResponse > ( response . Content ) ;
2014-08-25 05:54:45 +02:00
2014-09-14 17:10:51 +02:00
_data . ServerId = data . Id ;
_data . AccessKey = data . AccessKey ;
2014-08-25 05:54:45 +02:00
CacheData ( ) ;
}
}
2014-10-23 06:26:01 +02:00
private async Task UpdateServerRegistration ( string wanApiAddress , string localAddress )
2014-08-25 05:54:45 +02:00
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( wanApiAddress ) )
{
throw new ArgumentNullException ( "wanApiAddress" ) ;
}
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-02 21:44:06 +02:00
var url = "Servers" ;
2014-08-25 05:54:45 +02:00
url = GetConnectUrl ( url ) ;
2014-09-02 21:44:06 +02:00
url + = "?id=" + ConnectServerId ;
2014-08-25 05:54:45 +02:00
2014-10-23 06:26:01 +02: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 04:30:05 +02:00
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
2014-10-23 06:26:01 +02:00
options . SetPostData ( postData ) ;
2014-09-03 04:30:05 +02:00
2014-09-14 17:10:51 +02:00
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-08-25 05:54:45 +02:00
// No need to examine the response
2014-09-03 04:30:05 +02:00
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
2014-08-25 05:54:45 +02:00
{
}
}
2014-10-13 22:14:53 +02:00
private readonly object _dataFileLock = new object ( ) ;
2014-08-25 05:54:45 +02:00
private string CacheFilePath
{
get { return Path . Combine ( _appPaths . DataPath , "connect.txt" ) ; }
}
private void CacheData ( )
{
var path = CacheFilePath ;
try
{
2015-09-13 23:32:02 +02:00
_fileSystem . CreateDirectory ( Path . GetDirectoryName ( path ) ) ;
2014-08-25 05:54:45 +02:00
2014-09-14 17:10:51 +02:00
var json = _json . SerializeToString ( _data ) ;
2014-08-25 05:54:45 +02:00
var encrypted = _encryption . EncryptString ( json ) ;
2014-10-13 22:14:53 +02:00
lock ( _dataFileLock )
{
2015-09-13 23:32:02 +02:00
_fileSystem . WriteAllText ( path , encrypted , Encoding . UTF8 ) ;
2014-10-13 22:14:53 +02:00
}
2014-08-25 05:54:45 +02:00
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error saving data" , ex ) ;
}
}
private void LoadCachedData ( )
{
var path = CacheFilePath ;
try
{
2014-10-13 22:14:53 +02:00
lock ( _dataFileLock )
{
2015-09-13 23:32:02 +02:00
var encrypted = _fileSystem . ReadAllText ( path , Encoding . UTF8 ) ;
2014-08-25 05:54:45 +02:00
2014-10-13 22:14:53 +02:00
var json = _encryption . DecryptString ( encrypted ) ;
2014-08-25 05:54:45 +02:00
2014-10-13 22:14:53 +02:00
_data = _json . DeserializeFromString < ConnectData > ( json ) ;
}
2014-08-25 05:54:45 +02:00
}
catch ( IOException )
{
// File isn't there. no biggie
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error loading data" , ex ) ;
}
}
2014-09-14 17:10:51 +02: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 05:54:45 +02:00
private string GetConnectUrl ( string handler )
{
2015-08-28 06:19:08 +02:00
return "https://connect.emby.media/service/" + handler ;
2014-08-25 05:54:45 +02:00
}
2014-09-14 17:10:51 +02:00
2014-09-15 01:39:06 +02:00
public async Task < UserLinkResult > LinkUser ( string userId , string connectUsername )
2014-10-13 22:14:53 +02:00
{
2015-06-03 17:26:39 +02:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
await UpdateConnectInfo ( ) . ConfigureAwait ( false ) ;
}
2014-10-13 22:14:53 +02: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 17:10:51 +02:00
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( userId ) )
{
throw new ArgumentNullException ( "userId" ) ;
}
2014-09-14 17:10:51 +02:00
if ( string . IsNullOrWhiteSpace ( connectUsername ) )
{
throw new ArgumentNullException ( "connectUsername" ) ;
}
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-14 17:10:51 +02:00
var connectUser = await GetConnectUser ( new ConnectUserQuery
{
2014-11-04 13:41:12 +01:00
NameOrEmail = connectUsername
2014-09-14 17:10:51 +02:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-09-14 19:25:46 +02:00
if ( ! connectUser . IsActive )
{
2015-03-21 17:10:02 +01:00
throw new ArgumentException ( "The Emby account has been disabled." ) ;
2014-09-14 19:25:46 +02:00
}
2014-09-14 17:10:51 +02:00
var user = GetUser ( userId ) ;
if ( ! string . IsNullOrWhiteSpace ( user . ConnectUserId ) )
{
2014-10-14 06:22:17 +02:00
await RemoveConnect ( user , connectUser . Id ) . ConfigureAwait ( false ) ;
2014-09-14 17:10:51 +02:00
}
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
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 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-09-14 17:10:51 +02:00
2014-09-15 01:39:06 +02:00
var result = new UserLinkResult ( ) ;
2014-09-14 17:10:51 +02:00
// No need to examine the response
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
{
2014-09-14 19:12:47 +02:00
var response = _json . DeserializeFromStream < ServerUserAuthorizationResponse > ( stream ) ;
2014-09-15 01:39:06 +02:00
result . IsPending = string . Equals ( response . AcceptStatus , "waiting" , StringComparison . OrdinalIgnoreCase ) ;
2014-09-14 17:10:51 +02:00
}
user . ConnectAccessKey = accessToken ;
user . ConnectUserName = connectUser . Name ;
user . ConnectUserId = connectUser . Id ;
2014-09-15 01:39:06 +02:00
user . ConnectLinkType = UserLinkType . LinkedUser ;
2014-09-14 17:10:51 +02:00
await user . UpdateToRepository ( ItemUpdateType . MetadataEdit , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-09-15 01:39:06 +02:00
2014-12-20 07:06:27 +01:00
await _userManager . UpdateConfiguration ( user . Id . ToString ( "N" ) , user . Configuration ) ;
2014-10-13 22:14:53 +02:00
2014-10-14 06:22:17 +02:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
2014-09-15 01:39:06 +02:00
return result ;
2014-09-14 17:10:51 +02:00
}
2014-10-14 06:22:17 +02:00
2014-10-31 05:57:24 +01:00
public async Task < UserLinkResult > InviteUser ( ConnectAuthorizationRequest request )
2014-09-14 17:10:51 +02:00
{
2015-06-03 17:26:39 +02:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
await UpdateConnectInfo ( ) . ConfigureAwait ( false ) ;
}
2014-10-13 22:14:53 +02:00
await _operationLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
2014-09-14 17:10:51 +02:00
2014-10-13 22:14:53 +02:00
try
{
2014-10-31 05:57:24 +01:00
return await InviteUserInternal ( request ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
}
finally
{
_operationLock . Release ( ) ;
}
2014-09-14 17:10:51 +02:00
}
2014-10-31 05:57:24 +01:00
private async Task < UserLinkResult > InviteUserInternal ( ConnectAuthorizationRequest request )
2014-09-14 17:10:51 +02:00
{
2014-10-31 05:57:24 +01:00
var connectUsername = request . ConnectUserName ;
var sendingUserId = request . SendingUserId ;
2014-10-13 22:14:53 +02:00
if ( string . IsNullOrWhiteSpace ( connectUsername ) )
2014-09-14 17:10:51 +02:00
{
2014-10-13 22:14:53 +02:00
throw new ArgumentNullException ( "connectUsername" ) ;
}
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2014-09-14 17:10:51 +02:00
2014-11-19 03:45:12 +01: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 06:26:01 +02:00
string connectUserId = null ;
var result = new UserLinkResult ( ) ;
try
2014-10-13 22:14:53 +02:00
{
2014-10-23 06:26:01 +02:00
var connectUser = await GetConnectUser ( new ConnectUserQuery
{
2014-11-04 13:41:12 +01:00
NameOrEmail = connectUsername
2014-09-14 17:10:51 +02:00
2014-10-23 06:26:01 +02:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
2014-10-23 06:26:01 +02:00
if ( ! connectUser . IsActive )
{
2015-04-10 16:01:16 +02: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 06:26:01 +02:00
}
connectUserId = connectUser . Id ;
result . GuestDisplayName = connectUser . Name ;
}
catch ( HttpException ex )
2014-10-13 22:14:53 +02:00
{
2014-10-23 06:26:01 +02:00
if ( ! ex . StatusCode . HasValue | |
ex . StatusCode . Value ! = HttpStatusCode . NotFound | |
! Validator . EmailIsValid ( connectUsername ) )
{
throw ;
}
}
if ( string . IsNullOrWhiteSpace ( connectUserId ) )
{
return await SendNewUserInvitation ( requesterUserName , connectUsername ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
}
2014-09-14 17:10:51 +02:00
2014-10-13 22:14:53 +02:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
2014-09-14 17:10:51 +02:00
2014-10-13 22:14:53 +02:00
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
2014-09-14 19:12:47 +02:00
2014-10-13 22:14:53 +02:00
var accessToken = Guid . NewGuid ( ) . ToString ( "N" ) ;
2014-10-16 05:26:39 +02:00
2014-10-13 22:14:53 +02:00
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
2014-10-23 06:26:01 +02:00
{ "userId" , connectUserId } ,
2014-10-13 22:14:53 +02:00
{ "userType" , "Guest" } ,
{ "accessToken" , accessToken } ,
2014-10-16 05:26:39 +02:00
{ "requesterUserName" , requesterUserName }
2014-10-13 22:14:53 +02:00
} ;
2014-09-14 19:12:47 +02:00
2014-10-13 22:14:53 +02:00
options . SetPostData ( postData ) ;
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-10-13 22:14:53 +02: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 05:57:24 +01:00
2014-11-03 04:38:43 +01:00
_data . PendingAuthorizations . Add ( new ConnectAuthorizationInternal
2014-10-31 05:57:24 +01:00
{
ConnectUserId = response . UserId ,
Id = response . Id ,
ImageUrl = response . UserImageUrl ,
UserName = response . UserName ,
2015-01-20 06:19:13 +01:00
EnabledLibraries = request . EnabledLibraries ,
2015-01-13 04:46:44 +01:00
EnabledChannels = request . EnabledChannels ,
2014-11-03 04:38:43 +01:00
EnableLiveTv = request . EnableLiveTv ,
AccessToken = accessToken
2014-10-31 05:57:24 +01:00
} ) ;
CacheData ( ) ;
2014-10-13 22:14:53 +02:00
}
2014-10-14 06:22:17 +02:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
return result ;
}
2014-10-14 06:22:17 +02:00
2014-10-23 06:26:01 +02:00
private async Task < UserLinkResult > SendNewUserInvitation ( string fromName , string email )
{
var url = GetConnectUrl ( "users/invite" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
var postData = new Dictionary < string , string >
{
{ "email" , email } ,
{ "requesterUserName" , fromName }
} ;
options . SetPostData ( postData ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-10-23 06:26:01 +02:00
// No need to examine the response
using ( var stream = ( await _httpClient . Post ( options ) . ConfigureAwait ( false ) ) . Content )
{
}
2014-10-27 22:45:50 +01:00
2014-10-23 06:26:01 +02:00
return new UserLinkResult
{
IsNewUserInvitation = true ,
GuestDisplayName = email
} ;
}
2014-10-14 06:22:17 +02:00
public Task RemoveConnect ( string userId )
2014-10-13 22:14:53 +02:00
{
var user = GetUser ( userId ) ;
2014-10-14 06:22:17 +02:00
return RemoveConnect ( user , user . ConnectUserId ) ;
2014-10-13 22:14:53 +02:00
}
2014-10-14 06:22:17 +02:00
private async Task RemoveConnect ( User user , string connectUserId )
2014-10-13 22:14:53 +02:00
{
if ( ! string . IsNullOrWhiteSpace ( connectUserId ) )
{
await CancelAuthorizationByConnectUserId ( connectUserId ) . ConfigureAwait ( false ) ;
2014-09-14 17:10:51 +02:00
}
2014-09-14 19:12:47 +02:00
2014-09-14 17:10:51 +02:00
user . ConnectAccessKey = null ;
user . ConnectUserName = null ;
user . ConnectUserId = null ;
2014-10-14 06:22:17 +02:00
user . ConnectLinkType = null ;
2014-09-14 17:10:51 +02: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 13:41:12 +01:00
else if ( ! string . IsNullOrWhiteSpace ( query . NameOrEmail ) )
{
url = url + "?nameOrEmail=" + WebUtility . UrlEncode ( query . NameOrEmail ) ;
}
2014-09-14 17:10:51 +02:00
else if ( ! string . IsNullOrWhiteSpace ( query . Name ) )
{
2014-09-22 23:56:54 +02:00
url = url + "?name=" + WebUtility . UrlEncode ( query . Name ) ;
2014-09-14 17:10:51 +02:00
}
else if ( ! string . IsNullOrWhiteSpace ( query . Email ) )
{
2014-09-22 23:56:54 +02:00
url = url + "?name=" + WebUtility . UrlEncode ( query . Email ) ;
2014-09-14 17:10:51 +02:00
}
2014-11-05 00:50:26 +01:00
else
{
throw new ArgumentException ( "Empty ConnectUserQuery supplied" ) ;
}
2014-09-14 17:10:51 +02:00
var options = new HttpRequestOptions
{
CancellationToken = cancellationToken ,
Url = url
} ;
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-09-14 17:10:51 +02: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 19:25:46 +02:00
Name = response . Name ,
2014-10-14 06:22:17 +02:00
IsActive = response . IsActive ,
ImageUrl = response . ImageUrl
2014-09-14 17:10:51 +02:00
} ;
}
}
2014-11-30 20:01:33 +01:00
private void SetApplicationHeader ( HttpRequestOptions options )
{
options . RequestHeaders . Add ( "X-Application" , XApplicationValue ) ;
}
2014-09-14 17:10:51 +02:00
private void SetServerAccessToken ( HttpRequestOptions options )
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( ConnectAccessKey ) )
{
throw new ArgumentNullException ( "ConnectAccessKey" ) ;
}
2015-02-11 04:28:34 +01:00
2014-09-14 17:10:51 +02:00
options . RequestHeaders . Add ( "X-Connect-Token" , ConnectAccessKey ) ;
}
2014-10-12 19:31:41 +02:00
public async Task RefreshAuthorizations ( CancellationToken cancellationToken )
2014-10-12 20:12:20 +02:00
{
await _operationLock . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
try
{
2014-10-14 06:22:17 +02:00
await RefreshAuthorizationsInternal ( true , cancellationToken ) . ConfigureAwait ( false ) ;
2014-10-12 20:12:20 +02:00
}
finally
{
_operationLock . Release ( ) ;
}
}
2014-10-14 06:22:17 +02:00
private async Task RefreshAuthorizationsInternal ( bool refreshImages , CancellationToken cancellationToken )
2014-10-12 19:31:41 +02:00
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2015-02-11 04:28:34 +01:00
2014-10-12 19:31:41 +02:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
2014-10-13 22:14:53 +02:00
url + = "?serverId=" + ConnectServerId ;
2014-10-12 19:31:41 +02:00
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = cancellationToken
} ;
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-10-12 19:31:41 +02:00
try
{
2014-10-13 22:14:53 +02:00
using ( var stream = ( await _httpClient . SendAsync ( options , "GET" ) . ConfigureAwait ( false ) ) . Content )
2014-10-12 19:31:41 +02:00
{
var list = _json . DeserializeFromStream < List < ServerUserAuthorizationResponse > > ( stream ) ;
2014-10-14 06:22:17 +02:00
await RefreshAuthorizations ( list , refreshImages ) . ConfigureAwait ( false ) ;
2014-10-12 19:31:41 +02:00
}
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error refreshing server authorizations." , ex ) ;
}
}
2014-10-14 06:22:17 +02:00
private readonly SemaphoreSlim _connectImageSemaphore = new SemaphoreSlim ( 5 , 5 ) ;
private async Task RefreshAuthorizations ( List < ServerUserAuthorizationResponse > list , bool refreshImages )
2014-10-12 19:31:41 +02:00
{
2014-10-12 19:46:25 +02: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 06:26:01 +02:00
var deleteUser = user . ConnectLinkType . HasValue & &
user . ConnectLinkType . Value = = UserLinkType . Guest ;
2014-10-12 19:46:25 +02:00
user . ConnectUserId = null ;
user . ConnectAccessKey = null ;
user . ConnectUserName = null ;
2014-10-14 06:22:17 +02:00
user . ConnectLinkType = null ;
2014-10-12 19:46:25 +02:00
2014-10-12 20:12:20 +02:00
await _userManager . UpdateUser ( user ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
2014-10-23 06:26:01 +02:00
if ( deleteUser )
2014-10-12 19:52:43 +02:00
{
2014-10-13 22:14:53 +02:00
_logger . Debug ( "Deleting guest user {0}" , user . Name ) ;
2014-10-14 06:22:17 +02:00
await _userManager . DeleteUser ( user ) . ConfigureAwait ( false ) ;
2014-10-12 19:52:43 +02:00
}
2014-10-12 19:46:25 +02: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 19:52:43 +02:00
await _userManager . UpdateUser ( user ) . ConfigureAwait ( false ) ;
2014-10-12 19:46:25 +02:00
}
}
}
}
2014-10-31 05:57:24 +01:00
var currentPendingList = _data . PendingAuthorizations . ToList ( ) ;
2014-11-03 04:38:43 +01:00
var newPendingList = new List < ConnectAuthorizationInternal > ( ) ;
2014-10-13 22:14:53 +02:00
2014-10-12 19:52:43 +02:00
foreach ( var connectEntry in list )
{
2014-10-13 22:14:53 +02:00
if ( string . Equals ( connectEntry . UserType , "guest" , StringComparison . OrdinalIgnoreCase ) )
{
2014-10-31 05:57:24 +01:00
var currentPendingEntry = currentPendingList . FirstOrDefault ( i = > string . Equals ( i . Id , connectEntry . Id , StringComparison . OrdinalIgnoreCase ) ) ;
2014-10-13 22:14:53 +02:00
if ( string . Equals ( connectEntry . AcceptStatus , "accepted" , StringComparison . OrdinalIgnoreCase ) )
{
2014-10-16 05:26:39 +02:00
var user = _userManager . Users
. FirstOrDefault ( i = > string . Equals ( i . ConnectUserId , connectEntry . UserId , StringComparison . OrdinalIgnoreCase ) ) ;
2014-10-13 22:14:53 +02:00
if ( user = = null )
{
// Add user
2014-12-23 04:58:14 +01:00
user = await _userManager . CreateUser ( _userManager . MakeValidUsername ( connectEntry . UserName ) ) . ConfigureAwait ( false ) ;
2014-10-14 06:22:17 +02: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 07:06:27 +01: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 06:22:17 +02:00
2014-10-31 05:57:24 +01:00
if ( currentPendingEntry ! = null )
{
2015-01-20 06:19:13 +01:00
user . Policy . EnabledFolders = currentPendingEntry . EnabledLibraries ;
user . Policy . EnableAllFolders = false ;
2015-01-13 04:46:44 +01:00
user . Policy . EnabledChannels = currentPendingEntry . EnabledChannels ;
user . Policy . EnableAllChannels = false ;
2015-01-20 06:19:13 +01:00
user . Policy . EnableLiveTvAccess = currentPendingEntry . EnableLiveTv ;
2014-10-31 05:57:24 +01:00
}
2014-12-20 07:06:27 +01:00
await _userManager . UpdateConfiguration ( user . Id . ToString ( "N" ) , user . Configuration ) ;
2014-10-13 22:14:53 +02:00
}
}
else if ( string . Equals ( connectEntry . AcceptStatus , "waiting" , StringComparison . OrdinalIgnoreCase ) )
{
2014-11-03 04:38:43 +01:00
currentPendingEntry = currentPendingEntry ? ? new ConnectAuthorizationInternal ( ) ;
2014-10-31 05:57:24 +01:00
currentPendingEntry . ConnectUserId = connectEntry . UserId ;
currentPendingEntry . ImageUrl = connectEntry . UserImageUrl ;
currentPendingEntry . UserName = connectEntry . UserName ;
currentPendingEntry . Id = connectEntry . Id ;
2014-11-03 04:38:43 +01:00
currentPendingEntry . AccessToken = connectEntry . AccessToken ;
2014-10-31 05:57:24 +01:00
newPendingList . Add ( currentPendingEntry ) ;
2014-10-13 22:14:53 +02:00
}
}
}
2014-10-31 05:57:24 +01:00
_data . PendingAuthorizations = newPendingList ;
2014-10-13 22:14:53 +02:00
CacheData ( ) ;
2014-10-14 06:22:17 +02:00
await RefreshGuestNames ( list , refreshImages ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
}
2014-10-14 06:22:17 +02:00
private async Task RefreshGuestNames ( List < ServerUserAuthorizationResponse > list , bool refreshImages )
2014-10-13 22:14:53 +02:00
{
var users = _userManager . Users
. Where ( i = > ! string . IsNullOrEmpty ( i . ConnectUserId ) & &
2014-12-20 07:06:27 +01:00
( i . ConnectLinkType . HasValue & & i . ConnectLinkType . Value = = UserLinkType . Guest ) )
2014-10-14 06:22:17 +02:00
. ToList ( ) ;
2014-10-13 22:14:53 +02:00
foreach ( var user in users )
{
2014-10-14 06:22:17 +02:00
var authorization = list . FirstOrDefault ( i = > string . Equals ( i . UserId , user . ConnectUserId , StringComparison . Ordinal ) ) ;
2014-10-13 22:14:53 +02:00
2014-10-14 06:22:17 +02:00
if ( authorization = = null )
2014-10-12 19:52:43 +02:00
{
2014-10-14 06:22:17 +02:00
_logger . Warn ( "Unable to find connect authorization record for user {0}" , user . Name ) ;
continue ;
}
2014-10-13 22:14:53 +02:00
2014-12-20 07:06:27 +01:00
var syncConnectName = true ;
var syncConnectImage = true ;
if ( syncConnectName )
2014-10-13 22:14:53 +02:00
{
2014-10-14 06:22:17 +02:00
var changed = ! string . Equals ( authorization . UserName , user . Name , StringComparison . OrdinalIgnoreCase ) ;
2014-10-13 22:14:53 +02:00
if ( changed )
2014-10-12 19:52:43 +02:00
{
2014-10-14 06:22:17 +02:00
await user . Rename ( authorization . UserName ) . ConfigureAwait ( false ) ;
2014-10-12 19:52:43 +02:00
}
}
2014-10-13 22:14:53 +02:00
2014-12-20 07:06:27 +01:00
if ( syncConnectImage )
2014-10-13 22:14:53 +02:00
{
2014-10-14 06:22:17 +02:00
var imageUrl = authorization . UserImageUrl ;
2014-10-13 22:14:53 +02:00
if ( ! string . IsNullOrWhiteSpace ( imageUrl ) )
{
var changed = false ;
if ( ! user . HasImage ( ImageType . Primary ) )
{
changed = true ;
}
2014-10-14 06:22:17 +02:00
else if ( refreshImages )
2014-10-13 22:14:53 +02:00
{
using ( var response = await _httpClient . SendAsync ( new HttpRequestOptions
{
Url = imageUrl ,
BufferContent = false
} , "HEAD" ) . ConfigureAwait ( false ) )
{
var length = response . ContentLength ;
if ( length ! = new FileInfo ( user . GetImageInfo ( ImageType . Primary , 0 ) . Path ) . Length )
{
changed = true ;
}
}
}
if ( changed )
{
2014-10-14 06:22:17 +02:00
await _providerManager . SaveImage ( user , imageUrl , _connectImageSemaphore , ImageType . Primary , null , CancellationToken . None ) . ConfigureAwait ( false ) ;
2015-09-14 01:07:54 +02:00
await user . RefreshMetadata ( new MetadataRefreshOptions ( _fileSystem )
2014-10-13 22:14:53 +02:00
{
ForceSave = true ,
2014-10-14 06:22:17 +02:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
}
}
}
}
}
public async Task < List < ConnectAuthorization > > GetPendingGuests ( )
{
2014-10-14 06:22:17 +02: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 04:28:34 +01:00
catch ( Exception ex )
{
_logger . ErrorException ( "Error refreshing authorization" , ex ) ;
}
2014-10-14 06:22:17 +02:00
finally
{
_operationLock . Release ( ) ;
}
}
2014-11-03 04:38:43 +01:00
return _data . PendingAuthorizations . Select ( i = > new ConnectAuthorization
{
ConnectUserId = i . ConnectUserId ,
EnableLiveTv = i . EnableLiveTv ,
2015-01-13 04:46:44 +01:00
EnabledChannels = i . EnabledChannels ,
2015-01-20 06:19:13 +01:00
EnabledLibraries = i . EnabledLibraries ,
2014-11-03 04:38:43 +01:00
Id = i . Id ,
ImageUrl = i . ImageUrl ,
UserName = i . UserName
} ) . ToList ( ) ;
2014-10-13 22:14:53 +02: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 06:22:17 +02:00
await RefreshAuthorizationsInternal ( false , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-13 22:14:53 +02:00
}
private async Task CancelAuthorizationByConnectUserId ( string connectUserId )
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( connectUserId ) )
{
throw new ArgumentNullException ( "connectUserId" ) ;
}
if ( string . IsNullOrWhiteSpace ( ConnectServerId ) )
{
throw new ArgumentNullException ( "ConnectServerId" ) ;
}
2015-02-11 04:28:34 +01:00
2014-10-13 22:14:53 +02:00
var url = GetConnectUrl ( "ServerAuthorizations" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "userId" , connectUserId }
} ;
options . SetPostData ( postData ) ;
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-10-13 22:14:53 +02: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 19:52:43 +02:00
}
2014-10-12 19:31:41 +02:00
}
2014-10-17 06:52:41 +02:00
2015-03-17 06:58:29 +01:00
public async Task < ConnectSupporterSummary > GetConnectSupporterSummary ( )
{
if ( ! _securityManager . IsMBSupporter )
{
return new ConnectSupporterSummary ( ) ;
}
var url = GetConnectUrl ( "keyAssociation" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
2015-09-22 18:39:53 +02:00
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "supporterKey" , _securityManager . SupporterKey }
} ;
options . SetPostData ( postData ) ;
2015-03-17 06:58:29 +01:00
SetServerAccessToken ( options ) ;
SetApplicationHeader ( options ) ;
// No need to examine the response
2015-09-22 18:39:53 +02:00
using ( var stream = ( await _httpClient . SendAsync ( options , "POST" ) . ConfigureAwait ( false ) ) . Content )
2015-03-17 06:58:29 +01:00
{
return _json . DeserializeFromStream < ConnectSupporterSummary > ( stream ) ;
}
}
2015-03-17 16:57:06 +01:00
public async Task AddConnectSupporter ( string id )
{
if ( ! _securityManager . IsMBSupporter )
{
throw new InvalidOperationException ( ) ;
}
var url = GetConnectUrl ( "keyAssociation" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
2015-09-22 18:39:53 +02:00
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "supporterKey" , _securityManager . SupporterKey } ,
{ "userId" , id }
} ;
options . SetPostData ( postData ) ;
2015-03-17 16:57:06 +01:00
SetServerAccessToken ( options ) ;
SetApplicationHeader ( options ) ;
// No need to examine the response
using ( var stream = ( await _httpClient . SendAsync ( options , "POST" ) . ConfigureAwait ( false ) ) . Content )
{
}
}
2015-03-17 16:03:59 +01:00
public async Task RemoveConnectSupporter ( string id )
{
if ( ! _securityManager . IsMBSupporter )
{
throw new InvalidOperationException ( ) ;
}
var url = GetConnectUrl ( "keyAssociation" ) ;
var options = new HttpRequestOptions
{
Url = url ,
CancellationToken = CancellationToken . None
} ;
2015-09-22 18:39:53 +02:00
var postData = new Dictionary < string , string >
{
{ "serverId" , ConnectServerId } ,
{ "supporterKey" , _securityManager . SupporterKey } ,
{ "userId" , id }
} ;
options . SetPostData ( postData ) ;
2015-03-17 16:03:59 +01:00
SetServerAccessToken ( options ) ;
SetApplicationHeader ( options ) ;
// No need to examine the response
using ( var stream = ( await _httpClient . SendAsync ( options , "DELETE" ) . ConfigureAwait ( false ) ) . Content )
{
}
}
2014-10-17 06:52:41 +02:00
public async Task Authenticate ( string username , string passwordMd5 )
{
2014-11-05 00:50:26 +01:00
if ( string . IsNullOrWhiteSpace ( username ) )
{
throw new ArgumentNullException ( "username" ) ;
}
if ( string . IsNullOrWhiteSpace ( passwordMd5 ) )
{
throw new ArgumentNullException ( "passwordMd5" ) ;
}
2014-11-30 20:01:33 +01:00
var options = new HttpRequestOptions
2014-10-17 06:52:41 +02:00
{
Url = GetConnectUrl ( "user/authenticate" )
} ;
2014-11-30 20:01:33 +01:00
options . SetPostData ( new Dictionary < string , string >
2014-10-17 06:52:41 +02:00
{
{ "userName" , username } ,
{ "password" , passwordMd5 }
} ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2015-02-11 04:28:34 +01:00
2014-10-17 06:52:41 +02:00
// No need to examine the response
2014-11-30 20:01:33 +01:00
using ( var response = ( await _httpClient . SendAsync ( options , "POST" ) . ConfigureAwait ( false ) ) . Content )
2014-10-17 06:52:41 +02:00
{
}
}
2014-10-27 04:06:01 +01:00
async void _userManager_UserConfigurationUpdated ( object sender , GenericEventArgs < User > e )
{
var user = e . Argument ;
2014-11-09 04:18:14 +01:00
await TryUploadUserPreferences ( user , CancellationToken . None ) . ConfigureAwait ( false ) ;
2014-10-27 04:06:01 +01:00
}
private async Task TryUploadUserPreferences ( User user , CancellationToken cancellationToken )
{
2014-11-05 00:50:26 +01:00
if ( user = = null )
{
throw new ArgumentNullException ( "user" ) ;
}
2015-02-11 04:28:34 +01:00
2014-10-27 04:06:01 +01:00
if ( string . IsNullOrEmpty ( user . ConnectUserId ) )
{
return ;
}
if ( string . IsNullOrEmpty ( ConnectAccessKey ) )
{
return ;
}
var url = GetConnectUrl ( "user/preferences" ) ;
url + = "?userId=" + user . ConnectUserId ;
url + = "&key=userpreferences" ;
var options = new HttpRequestOptions
{
Url = url ,
2014-11-07 23:37:10 +01:00
CancellationToken = cancellationToken
2014-10-27 04:06:01 +01:00
} ;
2014-11-07 23:37:10 +01:00
var postData = new Dictionary < string , string > ( ) ;
postData [ "data" ] = _json . SerializeToString ( ConnectUserPreferences . FromUserConfiguration ( user . Configuration ) ) ;
options . SetPostData ( postData ) ;
2014-10-27 04:06:01 +01:00
SetServerAccessToken ( options ) ;
2014-11-30 20:01:33 +01:00
SetApplicationHeader ( options ) ;
2014-10-27 04:06:01 +01:00
try
{
// No need to examine the response
using ( var stream = ( await _httpClient . SendAsync ( options , "POST" ) . ConfigureAwait ( false ) ) . Content )
{
}
}
catch ( Exception ex )
{
_logger . ErrorException ( "Error uploading user preferences" , ex ) ;
}
}
private async Task DownloadUserPreferences ( User user , CancellationToken cancellationToken )
{
2014-10-27 22:45:50 +01:00
2014-10-27 04:06:01 +01:00
}
2014-11-03 04:38:43 +01: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 02:41:16 +02: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 04:38:43 +01: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 05:54:45 +02:00
}
}