Esempio n. 1
0
        /// <summary> Refresh the Paratext access token if expired with the given HttpClient. </summary>
        public async Task <Tokens> RefreshAccessTokenAsync(ParatextOptions options, Tokens paratextTokens,
                                                           HttpClient client)
        {
            bool expired = !paratextTokens.ValidateLifetime();

            if (!expired)
            {
                return(paratextTokens);
            }
            using (var request = new HttpRequestMessage(HttpMethod.Post, "api8/token"))
            {
                var requestObj = new JObject(
                    new JProperty("grant_type", "refresh_token"),
                    new JProperty("client_id", options.ClientId),
                    new JProperty("client_secret", options.ClientSecret),
                    new JProperty("refresh_token", paratextTokens.RefreshToken));
                request.Content = new StringContent(requestObj.ToString(), Encoding.Default, "application/json");
                HttpResponseMessage response = await client.SendAsync(request);

                await _exceptionHandler.EnsureSuccessStatusCode(response);

                string responseJson = await response.Content.ReadAsStringAsync();

                JObject responseObj = JObject.Parse(responseJson);
                return(new Tokens
                {
                    AccessToken = (string)responseObj["access_token"],
                    RefreshToken = (string)responseObj["refresh_token"]
                });
            }
        }
Esempio n. 2
0
        private async Task RefreshAccessTokenAsync(User user)
        {
            var request = new HttpRequestMessage(HttpMethod.Post, "api8/token");

            ParatextOptions options    = _options.Value;
            var             requestObj = new JObject(
                new JProperty("grant_type", "refresh_token"),
                new JProperty("client_id", options.ClientId),
                new JProperty("client_secret", options.ClientSecret),
                new JProperty("refresh_token", user.ParatextAccessToken.RefreshToken));

            request.Content = new StringContent(requestObj.ToString(), Encoding.UTF8, "application/json");
            HttpResponseMessage response = await _registryClient.SendAsync(request);

            response.EnsureSuccessStatusCode();

            string responseJson = await response.Content.ReadAsStringAsync();

            var responseObj = JObject.Parse(responseJson);

            user.ParatextAccessToken = new AccessTokenInfo
            {
                IdToken      = (string)responseObj["id_token"],
                AccessToken  = (string)responseObj["access_token"],
                RefreshToken = (string)responseObj["refresh_token"]
            };
            await _userRepo.UpdateAsync(user, b => b.Set(u => u.ParatextAccessToken, user.ParatextAccessToken));
        }
Esempio n. 3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SFInstallableDblResource" /> class.
 /// </summary>
 /// <param name="userSecret">The user secret.</param>
 /// <param name="paratextOptions">The paratext options.</param>
 /// <param name="restClientFactory">The rest client factory.</param>
 /// <param name="fileSystemService">The file system service.</param>
 /// <param name="jwtTokenHelper">The JWT token helper.</param>
 /// <remarks>
 /// This is a convenience constructor for unit tests.
 /// </remarks>
 internal SFInstallableDblResource(UserSecret userSecret, ParatextOptions paratextOptions,
                                   ISFRestClientFactory restClientFactory, IFileSystemService fileSystemService,
                                   IJwtTokenHelper jwtTokenHelper)
     : this(userSecret, paratextOptions, restClientFactory, fileSystemService, jwtTokenHelper,
            new ParatextProjectDeleter(), new ParatextMigrationOperations(),
            new ParatextZippedResourcePasswordProvider(paratextOptions))
 {
 }
        private async Task RefreshAccessTokenAsync(UserSecret userSecret)
        {
            ParatextOptions options = _paratextOptions.Value;

            userSecret.ParatextTokens = await _jwtTokenHelper.RefreshAccessTokenAsync(options,
                                                                                      userSecret.ParatextTokens, _registryClient);

            await _userSecretRepository.UpdateAsync(userSecret, b =>
                                                    b.Set(u => u.ParatextTokens, userSecret.ParatextTokens));
        }
Esempio n. 5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SFInstallableDblResource" /> class.
 /// </summary>
 /// <param name="userSecret">The user secret.</param>
 /// <param name="paratextOptions">The paratext options.</param>
 /// <param name="restClientFactory">The rest client factory.</param>
 /// <param name="fileSystemService">The file system service.</param>
 /// <param name="jwtTokenHelper">The JWT token helper.</param>
 /// <param name="projectDeleter">The project deleter.</param>
 /// <param name="migrationOperations">The migration operations.</param>
 /// <param name="passwordProvider">The password provider.</param>
 /// <exception cref="ArgumentNullException">restClientFactory</exception>
 private SFInstallableDblResource(UserSecret userSecret, ParatextOptions paratextOptions,
                                  ISFRestClientFactory restClientFactory, IFileSystemService fileSystemService,
                                  IJwtTokenHelper jwtTokenHelper, IProjectDeleter projectDeleter,
                                  IMigrationOperations migrationOperations, IZippedResourcePasswordProvider passwordProvider)
     : base(projectDeleter, migrationOperations, passwordProvider)
 {
     this._userSecret        = userSecret;
     this._paratextOptions   = paratextOptions;
     this._restClientFactory = restClientFactory;
     this._fileSystemService = fileSystemService;
     this._jwtTokenHelper    = jwtTokenHelper;
     if (this._restClientFactory == null)
     {
         throw new ArgumentNullException(nameof(restClientFactory));
     }
     else if (this._fileSystemService == null)
     {
         throw new ArgumentNullException(nameof(fileSystemService));
     }
 }
Esempio n. 6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ParatextZippedResourcePasswordProvider"/> class.
 /// </summary>
 /// <param name="paratextOptions">The paratext options.</param>
 internal ParatextZippedResourcePasswordProvider(ParatextOptions paratextOptions)
 {
     this._paratextOptions = paratextOptions;
 }
Esempio n. 7
0
        /// <summary>
        /// Converts the JSON response to a list of Installable DBL Resources.
        /// </summary>
        /// <param name="baseUri">The base URI.</param>
        /// <param name="response">The response.</param>
        /// <param name="restClientFactory">The rest client factory.</param>
        /// <param name="fileSystemService">The file system service.</param>
        /// <param name="jwtTokenHelper">The JWT token helper.</param>
        /// <param name="createdTimestamp">The created timestamp.</param>
        /// <param name="userSecret">The user secret.</param>
        /// <param name="paratextOptions">The paratext options.</param>
        /// <param name="projectDeleter">The project deleter.</param>
        /// <param name="migrationOperations">The migration operations.</param>
        /// <param name="passwordProvider">The password provider.</param>
        /// <returns>
        /// The Installable Resources.
        /// </returns>
        private static IEnumerable <SFInstallableDblResource> ConvertJsonResponseToInstallableDblResources(
            string baseUri, string response, ISFRestClientFactory restClientFactory,
            IFileSystemService fileSystemService, IJwtTokenHelper jwtTokenHelper, DateTime createdTimestamp,
            UserSecret userSecret, ParatextOptions paratextOptions, IProjectDeleter projectDeleter,
            IMigrationOperations migrationOperations, IZippedResourcePasswordProvider passwordProvider)
        {
            if (!string.IsNullOrWhiteSpace(response))
            {
                JObject jsonResources;
                try
                {
                    jsonResources = JObject.Parse(response);
                }
                catch (JsonReaderException)
                {
                    // Ignore the exception and just return empty result
                    // This is probably caused by partial result from poor connection to DBL
                    yield break;
                }
                foreach (JToken jsonResource in jsonResources["resources"] as JArray ?? new JArray())
                {
                    var name       = (string)jsonResource["name"];
                    var nameCommon = (string)jsonResource["nameCommon"];
                    var fullname   = (string)jsonResource["fullname"];
                    if (string.IsNullOrWhiteSpace(fullname))
                    {
                        fullname = nameCommon;
                    }

                    var        languageName        = (string)jsonResource["languageName"];
                    var        id                  = (string)jsonResource["id"];
                    var        revision            = (string)jsonResource["revision"];
                    var        permissionsChecksum = (string)jsonResource["permissions-checksum"];
                    var        manifestChecksum    = (string)jsonResource["p8z-manifest-checksum"];
                    var        languageIdLdml      = (string)jsonResource["languageLDMLId"];
                    var        languageIdCode      = (string)jsonResource["languageCode"];
                    LanguageId languageId          =
                        migrationOperations.DetermineBestLangIdToUseForResource(languageIdLdml, languageIdCode);
                    if (string.IsNullOrEmpty(languageId.Id))
                    {
                        languageId = LanguageIdHelper.FromCommonLanguageName(languageName);
                    }
                    else
                    {
                        languageId = LanguageId.FromEthnologueCode(languageId.Id);
                    }

                    string url      = BuildDblResourceEntriesUrl(baseUri, id);
                    var    resource = new SFInstallableDblResource(userSecret, paratextOptions, restClientFactory,
                                                                   fileSystemService, jwtTokenHelper, projectDeleter, migrationOperations, passwordProvider)
                    {
                        DisplayName         = name,
                        Name                = name,
                        FullName            = fullname,
                        LanguageID          = languageId,
                        DblSourceUrl        = url,
                        DBLEntryUid         = id,
                        DBLRevision         = int.Parse(revision),
                        PermissionsChecksum = permissionsChecksum,
                        ManifestChecksum    = manifestChecksum,
                        CreatedTimestamp    = createdTimestamp,
                    };

                    resource.LanguageName = MacroLanguageHelper.GetMacroLanguage(resource.LanguageID) ?? languageName;

                    yield return(resource);
                }
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Return a list of resources which this user is allowed to install from DBL.
        /// If we cannot contact DBL, return an empty list.
        /// </summary>
        /// <param name="userSecret">The user secret.</param>
        /// <param name="paratextOptions">The paratext options.</param>
        /// <param name="restClientFactory">The rest client factory.</param>
        /// <param name="fileSystemService">The file system service.</param>
        /// <param name="jwtTokenHelper">The JWT token helper.</param>
        /// <param name="baseUrl">The base URL.</param>
        /// <returns>The Installable Resources.</returns>
        /// <exception cref="ArgumentNullException">restClientFactory
        /// or
        /// userSecret</exception>
        /// <remarks>Tests on this method can be found in ParatextServiceTests.cs calling GetResources().</remarks>
        public static IEnumerable <SFInstallableDblResource> GetInstallableDblResources(UserSecret userSecret,
                                                                                        ParatextOptions paratextOptions, ISFRestClientFactory restClientFactory,
                                                                                        IFileSystemService fileSystemService, IJwtTokenHelper jwtTokenHelper, IExceptionHandler exceptionHandler,
                                                                                        string baseUrl = null)
        {
            // Parameter check (just like the constructor)
            if (restClientFactory == null)
            {
                throw new ArgumentNullException(nameof(restClientFactory));
            }
            else if (userSecret == null)
            {
                throw new ArgumentNullException(nameof(userSecret));
            }

            ISFRestClient client =
                restClientFactory.Create(string.Empty, ApplicationProduct.DefaultVersion, userSecret);

            baseUrl = string.IsNullOrWhiteSpace(baseUrl) ? InternetAccess.ParatextDBLServer : baseUrl;
            string response = null;

            try
            {
                response = client.Get(BuildDblResourceEntriesUrl(baseUrl));
            }
            catch (WebException e)
            {
                // If we get a temporary 401 Unauthorized response, return an empty list.
                string errorExplanation = "GetInstallableDblResources failed when attempting to inquire about"
                                          + $" resources and is ignoring error {e}";
                var report = new Exception(errorExplanation);
                // Report to bugsnag, but don't throw.
                exceptionHandler.ReportException(report);
                return(Enumerable.Empty <SFInstallableDblResource>());
            }
            IEnumerable <SFInstallableDblResource> resources = ConvertJsonResponseToInstallableDblResources(baseUrl,
                                                                                                            response, restClientFactory, fileSystemService, jwtTokenHelper, DateTime.Now, userSecret,
                                                                                                            paratextOptions, new ParatextProjectDeleter(), new ParatextMigrationOperations(),
                                                                                                            new ParatextZippedResourcePasswordProvider(paratextOptions));

            return(resources);
        }
Esempio n. 9
0
        /// <summary>
        /// Checks the resource permission.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <param name="userSecret">The user secret.</param>
        /// <param name="paratextOptions">The paratext options.</param>
        /// <param name="restClientFactory">The rest client factory.</param>
        /// <param name="fileSystemService">The file system service.</param>
        /// <param name="jwtTokenHelper">The JWT token helper.</param>
        /// <param name="baseUrl">The base URL.</param>
        /// <returns>
        ///   <c>true</c> if the user has permission to access the resource; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="ArgumentNullException">id
        /// or
        /// userSecret
        /// or
        /// restClientFactory</exception>
        public static bool CheckResourcePermission(string id, UserSecret userSecret,
                                                   ParatextOptions paratextOptions, ISFRestClientFactory restClientFactory,
                                                   IFileSystemService fileSystemService, IJwtTokenHelper jwtTokenHelper,
                                                   IExceptionHandler exceptionHandler, string baseUrl = null)
        {
            // Parameter check
            if (string.IsNullOrWhiteSpace(id))
            {
                throw new ArgumentNullException(nameof(id));
            }
            else if (userSecret == null)
            {
                throw new ArgumentNullException(nameof(userSecret));
            }
            else if (restClientFactory == null)
            {
                throw new ArgumentNullException(nameof(restClientFactory));
            }

            ISFRestClient client = restClientFactory.Create(string.Empty, ApplicationProduct.DefaultVersion, userSecret);

            baseUrl = string.IsNullOrWhiteSpace(baseUrl) ? InternetAccess.ParatextDBLServer : baseUrl;
            try
            {
                _ = client.Head(BuildDblResourceEntriesUrl(baseUrl, id));
                return(true);
            }
            catch (Exception ex)
            {
                // Normally we would catch the specific WebException,
                // but something in ParatextData is interfering with it.
                if (ex.InnerException?.Message.StartsWith("401: ", StringComparison.OrdinalIgnoreCase) ?? false)
                {
                    // A 401 error means unauthorized (probably a bad token)
                    return(false);
                }
                else if (ex.InnerException?.Message.StartsWith("403: ", StringComparison.OrdinalIgnoreCase) ?? false)
                {
                    // A 403 error means no access.
                    return(false);
                }
                else if (ex.InnerException?.Message.StartsWith("404: ", StringComparison.OrdinalIgnoreCase) ?? false)
                {
                    // A 404 error means that the resource is not on the server
                    return(false);
                }
                else if (ex.InnerException?.Message.StartsWith("405: ", StringComparison.OrdinalIgnoreCase) ?? false)
                {
                    // A 405 means that HEAD request does not work on the server, so we will use the resource list
                    // This is slower (although faster than a GET request on the resource), but more reliable
                    IEnumerable <SFInstallableDblResource> resources =
                        GetInstallableDblResources(
                            userSecret,
                            paratextOptions,
                            restClientFactory,
                            fileSystemService,
                            jwtTokenHelper,
                            exceptionHandler,
                            baseUrl);
                    return(resources.Any(r => r.DBLEntryUid == id));
                }
                else if (ex.Source == "NSubstitute")
                {
                    // This occurs during unit tests to test whether there is permission or not
                    return(false);
                }
                else
                {
                    // An unknown error
                    throw;
                }
            }
        }