예제 #1
0
        /// <summary>
        /// Logs the NewCardInfo member of the specified NewCardPayload object with obfuscated fields where required.
        /// </summary>
        /// <param name="newCardInfo">
        /// The NewCardInfo object to obfuscate and log.
        /// </param>
        /// <param name="context">
        /// The context of the current request.
        /// </param>
        internal static void LogObfuscatedNewCardInfo(NewCardInfo newCardInfo,
                                                      CommerceContext context)
        {
            string number = newCardInfo.Number;

            if (String.IsNullOrWhiteSpace(number) == false && number.Length >= 4)
            {
                number = number.Substring(number.Length - 4, 4);
            }

            string logInfo = string.Empty;

            if (newCardInfo != null)
            {
                NewCardInfo obfuscatedNewCardInfo = new NewCardInfo()
                {
                    CardBrand  = newCardInfo.CardBrand,
                    Expiration = newCardInfo.Expiration,
                    NameOnCard = newCardInfo.NameOnCard,
                    Number     = number
                };
                logInfo = General.SerializeJson(obfuscatedNewCardInfo);
            }

            context.Log.Verbose("Obfuscated NewCardInfo:\r\n{0}", logInfo);
        }
예제 #2
0
        /// <summary>
        /// Populates the User and Card object within the current Context object.
        /// </summary>
        private void PopulateContextUserAndCard()
        {
            // Populate the Context InitialUser from the discovered User.
            User user = (User)Context[Key.User];

            Context[Key.InitialUser] = new User(user);

            RewardPrograms rewardPrograms = RewardPrograms.CardLinkOffers;

            if (Context.ContainsKey(Key.RewardProgramType) == true)
            {
                rewardPrograms = (RewardPrograms)Context[Key.RewardProgramType];
            }

            // Build a Card from the discovered User and specified NewCardInfo.
            NewCardInfo newCardInfo = (NewCardInfo)Context[Key.NewCardInfo];
            int         year        = newCardInfo.Expiration.Year;
            int         month       = newCardInfo.Expiration.Month;

            Context[Key.Card] = new Card(user.GlobalId)
            {
                NameOnCard     = newCardInfo.NameOnCard,
                LastFourDigits = newCardInfo.Number.Substring(newCardInfo.Number.Length - 4, 4),
                Expiration     = new DateTime(year, month, DateTime.DaysInMonth(year, month)),
                CardBrand      = ParseCardBrand(newCardInfo.CardBrand),
                RewardPrograms = rewardPrograms
            };
        }
예제 #3
0
        /// <summary>
        /// Generates a legacy NewCardInfo object for the specified credit card number.
        /// </summary>
        /// <param name="newCardNumber">
        /// The object containing the number for which to generate a legacy NewCardInfo object.
        /// </param>
        /// <returns>
        /// The generated NewCardInfo object.
        /// </returns>
        /// <remarks>
        /// When the V1 AddCard and GetCard APIs are removed, legacy compatibility can be removed from all layers.
        /// </remarks>
        internal static NewCardInfo GenerateLegacyCardInfo(NewCardNumber newCardNumber)
        {
            string      number = newCardNumber.Number;
            NewCardInfo result = new NewCardInfo
            {
                Expiration = DateTime.MaxValue,
                Number     = number,
                FlightId   = newCardNumber.FlightId
            };

            if (String.IsNullOrWhiteSpace(number) == false)
            {
                switch (number[0])
                {
                case '4':
                    result.CardBrand = "Visa";
                    break;

                case '5':
                    result.CardBrand = "MasterCard";
                    break;

                case '3':
                    if (number[1] == '4' || number[1] == '7')
                    {
                        result.CardBrand = "AmericanExpress";
                    }
                    break;
                }
            }

            return(result);
        }
예제 #4
0
        /// <summary>
        /// Checks whether Card number matches the rejection list.
        /// </summary>
        /// <returns>
        /// * True if the card matches rejection list.
        /// * Else returns false.
        /// </returns>
        /// <remarks>
        /// This method takes configurable rejection list from Configuration and checks the card number against it.
        /// </remarks>
        internal bool CardProviderRejected()
        {
            bool result = false;

            if (ListCardProviderRejectionMask == null)
            {
                string rejectMask = CommerceServiceConfig.Instance.CardProviderRejectionMask;
                ListCardProviderRejectionMask = rejectMask.Split(';');
            }

            NewCardInfo newCardInfo = (NewCardInfo)Context[Key.NewCardInfo];
            string      cardNumber  = newCardInfo.Number;

            foreach (string regEx in ListCardProviderRejectionMask)
            {
                if (regEx.Length > 0)
                {
                    if (Regex.IsMatch(cardNumber, regEx) == true)
                    {
                        result = true;
                        break;
                    }
                }
            }
            return(result);
        }
예제 #5
0
        public Task <HttpResponseMessage> Add(NewCardNumber newCardNumber)
        {
            Stopwatch callTimer = Stopwatch.StartNew();

            Task <HttpResponseMessage> result;

            // Build a context object to pass down the pipeline.
            CommerceContext context = CommerceContext.BuildAsynchronousRestContext("Add card and queue claiming already claimed deals",
                                                                                   Request, new AddCardResponse(), callTimer);

            try
            {
                if (newCardNumber == null)
                {
                    throw new ArgumentNullException("newCardNumber", "Parameter newCardNumber cannot be null.");
                }

                context.Log.Information("Processing {0} call.", context.ApiCallDescription);

                // Generate a legacy NewCardInfo object from the specified number.
                NewCardInfo newCardInfo = ControllerUtilities.GenerateLegacyCardInfo(newCardNumber);
                ControllerUtilities.LogObfuscatedNewCardInfo(newCardInfo, context);

                // Add parameters of the call to the context.
                context[Key.QueueJob]          = true;
                context[Key.NewCardInfo]       = newCardInfo;
                context[Key.GlobalUserId]      = CommerceContext.PopulateUserId(context);
                context[Key.ReferrerId]        = newCardNumber.Referrer;
                context[Key.RewardProgramType] = ControllerUtilities.GetRewardProgramAssociatedWithRequest(this.Request);

                // Create an executor object to execute the API invocation.
                AddCardExecutor executor = new AddCardExecutor(context);
                Task.Factory.StartNew(async() => await executor.Execute());

                result = ((TaskCompletionSource <HttpResponseMessage>)context[Key.TaskCompletionSource]).Task;
            }
            catch (Exception ex)
            {
                result = RestResponder.CreateExceptionTask(context, ex);
            }

            return(result);
        }
예제 #6
0
        public Task <HttpResponseMessage> Add(AddCardPayload payload)
        {
            Stopwatch callTimer = Stopwatch.StartNew();

            if (payload == null)
            {
                throw new ArgumentNullException("payload", "Parameter payload cannot be null.");
            }

            // Build a context object to pass down the pipeline.
            CommerceContext context = CommerceContext.BuildAsynchronousRestContext("Create account for unauthenticated user, add card, and queue claiming deals",
                                                                                   Request, new UnauthenticatedAddCardResponse(), callTimer);

            context.Log.Information("Processing {0} call.", context.ApiCallDescription);

            // Generate a legacy NewCardInfo object from the specified number.
            NewCardInfo newCardInfo = ControllerUtilities.GenerateLegacyCardInfo(new NewCardNumber {
                Number = payload.Number
            });

            ControllerUtilities.LogObfuscatedNewCardInfo(newCardInfo, context);

            // Add parameters of the call to the context.
            context[Key.CreateUnauthenticatedAccount] = true;
            context[Key.EmailAddress]      = payload.Email;
            context[Key.ReferrerId]        = payload.Referrer;
            context[Key.UserLocation]      = payload.UserLocation;
            context[Key.ReferralEvent]     = ReferralEvent.Signup;
            context[Key.QueueJob]          = true;
            context[Key.NewCardInfo]       = newCardInfo;
            context[Key.RewardProgramType] = ControllerUtilities.GetRewardProgramAssociatedWithRequest(this.Request);

            // Create an executor object to execute the API invocation.
            AddCardExecutor executor = new AddCardExecutor(context);

            Task.Factory.StartNew(async() => await executor.Execute());

            return(((TaskCompletionSource <HttpResponseMessage>)context[Key.TaskCompletionSource]).Task);
        }
예제 #7
0
 public NewCardInfo GetNewCardInfo()
 {
     NewCardInfo cardinfo = new NewCardInfo();
     return cardinfo;
 }
예제 #8
0
        /// <summary>
        /// Performs preliminary checks to determine whether the card may be valid.
        /// </summary>
        /// <returns>
        /// * True if the card may be valid.
        /// * Else returns false.
        /// </returns>
        /// <remarks>
        /// This method does not determine whether the card actually _is_ valid, i.e. whether it can be used to make
        /// purchases, belongs to the specified person, etc.. Instead, it determines whether the card _may be_ valid, by
        /// ensuring the card brand matches the card number, that the stated expiration date is not in the past, and that the
        /// card number is valid according to Luhn's modulus 10 algorithm.
        /// </remarks>
        internal bool CardMayBeValid()
        {
            bool result = false;

            Context.Log.Verbose("Determining if NewCardInfo object may be valid.");

            // Ensure the card number matches the card brand.
            NewCardInfo newCardInfo = (NewCardInfo)Context[Key.NewCardInfo];

            if (String.IsNullOrWhiteSpace(newCardInfo.Number) == false && (newCardInfo.Number[0] - '0') == (int)ParseCardBrand(newCardInfo.CardBrand))
            {
                // Get baseline DateTime for the last day of the current month.
                DateTime currentDate       = DateTime.UtcNow;
                int      year              = currentDate.Year;
                int      month             = currentDate.Month;
                int      lastDayOfMonth    = DateTime.DaysInMonth(year, month);
                DateTime endOfCurrentMonth = new DateTime(year, month, lastDayOfMonth);

                // Get baseline DateTime for the last day of the month in which the card expires.
                year           = newCardInfo.Expiration.Year;
                month          = newCardInfo.Expiration.Month;
                lastDayOfMonth = DateTime.DaysInMonth(year, month);
                DateTime endOfExpirationMonth = new DateTime(year, month, lastDayOfMonth);

                // If the card has not expired, continue validation.
                if (endOfExpirationMonth >= endOfCurrentMonth)
                {
                    // Validate card number using Luhn's algorithm.
                    // Luhn's algorithm works by starting from the last (check) digit in the credit card number and then, for the
                    // check digit and every second previous digit, adding those digits into a total, and, for all other
                    // digits, multiplying those digits by 2, adding the resulting digits together, and adding those sums into
                    // the total. Those modified values are determinant, and can therefore be represented in an array for fast
                    // runtime lookups.
                    int  checksum      = 0;
                    bool modifyDigits  = false;
                    bool nonDigitFound = false;
                    for (int count = newCardInfo.Number.Length - 1; count >= 0; count--)
                    {
                        int digit = newCardInfo.Number[count] - '0';
                        if (digit < 0 || digit > 9)
                        {
                            nonDigitFound = true;
                            break;
                        }

                        if (modifyDigits == false)
                        {
                            checksum += digit;
                        }
                        else
                        {
                            checksum += LuhnModifiedValues[digit];
                        }

                        modifyDigits = !modifyDigits;
                    }

                    if (nonDigitFound == false)
                    {
                        result = checksum % 10 == 0;
                    }
                }
            }

            if (result == true)
            {
                Context.Log.Verbose("NewCardInfo may be valid.");
            }
            else
            {
                Context.Log.Verbose("NewCardInfo cannot be valid.");
            }

            return(result);
        }
예제 #9
0
        /// <summary>
        /// Invokes AddCard with each currently registered partner.
        /// </summary>
        public async Task Invoke()
        {
            try
            {
                ResultCode resultCode = ResultCode.Created;

                NewCardInfo             newCardInfo = (NewCardInfo)Context[Key.NewCardInfo];
                Card                    card        = (Card)Context[Key.Card];
                List <ICommercePartner> partners    = new List <ICommercePartner>();

                //partners.Add(new FirstData(Context));
                CardBrand cardBrand = (CardBrand)Enum.Parse(typeof(CardBrand), newCardInfo.CardBrand);
                switch (cardBrand)
                {
                case CardBrand.AmericanExpress:
                    partners.Add(new Amex(Context));
                    break;

                case CardBrand.MasterCard:
                    partners.Add(new MasterCard(Context));
                    break;

                case CardBrand.Visa:
                    partners.Add(new Visa(Context));
                    break;
                }

                foreach (ICommercePartner partner in partners)
                {
                    string partnerName = partner.GetType().Name;
                    Context.Log.Verbose("Adding card to partner {0}.", partnerName);

                    ResultCode partnerResult = ResultCode.None;
                    try
                    {
                        partnerResult = await partner.AddCardAsync();
                    }
                    catch (Exception ex)
                    {
                        Context.Log.Error("Add card call to partner {0} ended with an error.", ex, partnerName);
                    }

                    // Update overall result from result of call to partner.
                    switch (partnerResult)
                    {
                    case ResultCode.Created:
                        // At this time, FirstData PartnerCardId is used as the PanToken for the card.
                        if (partner is FirstData)
                        {
                            PartnerCardInfo firstDataInfo = card.PartnerCardInfoList.SingleOrDefault(info => info.PartnerId == Partner.FirstData);
                            if (firstDataInfo != null)
                            {
                                card.PanToken = firstDataInfo.PartnerCardId;
                            }
                        }
                        break;

                    case ResultCode.InvalidCard:
                        resultCode = ResultCode.InvalidCard;
                        break;

                    case ResultCode.UnknownError:
                        resultCode = ResultCode.UnknownError;
                        break;

                    case ResultCode.InvalidCardNumber:
                        resultCode = ResultCode.InvalidCardNumber;
                        break;

                    case ResultCode.CorporateOrPrepaidCardError:
                        resultCode = ResultCode.CorporateOrPrepaidCardError;
                        break;

                    case ResultCode.MaximumEnrolledCardsLimitReached:
                        resultCode = ResultCode.MaximumEnrolledCardsLimitReached;
                        break;

                    case ResultCode.CardRegisteredToDifferentUser:
                        resultCode = ResultCode.CardRegisteredToDifferentUser;
                        break;

                    case ResultCode.CardExpired:
                        resultCode = ResultCode.CardExpired;
                        break;

                    default:
                        throw new InvalidOperationException("Call to partner invoker returned ResultCode.None.");
                    }
                }
                AddCardConcluder addCardConcluder = new AddCardConcluder(Context);
                addCardConcluder.Conclude(resultCode);
            }
            catch (Exception ex)
            {
                RestResponder.BuildAsynchronousResponse(Context, ex);
            }
        }