public async Task <ServiceProviderResponse> StartOtpAsync(
            [FromHeader(Constant.OperationTrackingIdHeader)] string requestId,
            [FromHeader] string account,
            [FromBody] OtpPushDescription description)
        {
            Validator.ArgumentNotNull(account, nameof(account));
            Validator.ArgumentNotNull(description, nameof(description));
            Validator.ArgumentNotNullOrEmpty(description.TemplateName, nameof(description.TemplateName));
            Validator.ArgumentNotNullOrEmpty(description.PhoneNumber, nameof(description.PhoneNumber));
            if (description.ExpireTime == null)
            {
                description.ExpireTime = DefaultExpireTime;
            }

            if (description.CodeLength == null)
            {
                description.CodeLength = DefaultCodeLength;
            }

            if (description.Channel == null)
            {
                description.Channel = DefaultChannel;
            }

            if (description.ExpireTime < 60 || description.ExpireTime > 3600)
            {
                throw new ArgumentException($"ExpireTime should be a value between 60 and 3600.");
            }

            if (description.CodeLength < 4 || description.CodeLength > 10)
            {
                throw new ArgumentException($"CodeLength should be a value between 4 and 10.");
            }

            var result = await this.engine.OtpPushAsync(account, description, this.otpRequest, requestId, CancellationToken.None);

            return(result);
        }
Example #2
0
        public async Task <ServiceProviderResponse> OtpPushAsync(string account, OtpPushDescription description, ServiceProviderRequest request, string requestId, CancellationToken cancellationToken)
        {
            var channel     = OtpChannelHelper.Format(description.Channel);
            var smsProvider = ProviderManager.GetSmsServiceProvider();

            // Check if templete type is 2
            var smsGetRequest = new ServiceProviderRequest
            {
                HttpMethod          = "GET",
                Path                = "templates/" + description.TemplateName,
                Content             = string.Empty,
                Headers             = request.Headers,
                QueryNameValuePairs = request.QueryNameValuePairs,
            };
            var subscriptionId = await RequestHelper.GetSubscriptionId(account);

            try
            {
                var result = await smsProvider.OnRequestAsync(smsGetRequest);

                var    projson = JObject.Parse(result.Content);
                JToken tpltype;
                if (projson.TryGetValue("tplType", out tpltype) && ((int)tpltype != 2))
                {
                    throw new ArgumentException($"Invalid template type.");
                }

                // generate otpCode
                var code = GetOtpCode((int)description.CodeLength);

                // prepare messageSendRequest for sending request to sms provider
                MessageSendRequest messageSendRequest = new MessageSendRequest()
                {
                    Targets = new List <string>()
                    {
                        description.PhoneNumber
                    },
                    MessageBody = new MessageTemplateBody()
                    {
                        TemplateName       = description.TemplateName,
                        TemplateParameters = new PropertyCollection <string>()
                    }
                };
                messageSendRequest.MessageBody.TemplateParameters.Add("otpcode", code);
                var content = JsonConvert.SerializeObject(messageSendRequest);

                // create request for sms provider
                var smsRequest = new ServiceProviderRequest
                {
                    HttpMethod          = "POST",
                    Path                = "messages",
                    Content             = content,
                    Headers             = request.Headers,
                    QueryNameValuePairs = request.QueryNameValuePairs
                };

                // send push request to sms provider
                result = await smsProvider.OnRequestAsync(smsRequest);

                if (result.StatusCode != HttpStatusCode.OK)
                {
                    return(result);
                }

                // Create otp record in db
                var otpcode = await this.otpStore.CreateorUpdateOtpCodeAsync(account, description.PhoneNumber, code, (int)description.ExpireTime);

                // Create otp check history in otp storage table
                await this.otpStorage.CreateOtpCodeHistoryRecord(account, description.PhoneNumber, ActionType.Start.ToString(), DateTime.UtcNow);

                this.metricManager.LogOtpSendSuccess(1, account, subscriptionId, description.Channel);
                OtpProviderEventSource.Current.Info(requestId, this, nameof(this.OtpPushAsync), OperationStates.Succeeded, $"account: {account}, channel: {channel}, phoneNumber: {description.PhoneNumber}");
                return(new ServiceProviderResponse
                {
                    StatusCode = HttpStatusCode.OK,
                    JsonContent = new OtpStartOperationResult
                    {
                        ExpireTime = (int)description.ExpireTime
                    }
                });
            }
            catch (Exception ex)
            {
                this.metricManager.LogOtpSendFailed(1, account, subscriptionId, description.Channel);
                while (ex is AggregateException)
                {
                    ex = ex.InnerException;
                }

                OtpProviderEventSource.Current.ErrorException(requestId, this, nameof(this.OtpPushAsync), OperationStates.Failed, $"Failed to send OTP code for account: {account}, channel: {channel}, phoneNumber: {description.PhoneNumber}", ex);

                if ((ex is ArgumentException) || (ex is QuotaExceededException))
                {
                    throw ex;
                }

                throw new Exception(string.Format($"Failed to send OTP code for account: {account}, channel: {channel}, phoneNumber: {description.PhoneNumber}"));
            }
        }