ccvalidate.py :  » Database » PyDO » skunkweb-3.4.4 » pylibs » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Database » PyDO 
PyDO » skunkweb 3.4.4 » pylibs » ccvalidate.py
#  
#  Copyright (C) 2003 Jacob Smullyan <smulloni@smullyan.org>
#  
#      You may distribute under the terms of either the GNU General
#      Public License or the SkunkWeb License, as specified in the
#      README file.
#   
# Time-stamp: <03/06/09 18:06:53 smulloni>

"""
contains a function for validating credit card numbers.
Supported card types are MasterCard, Visa, Amex, Diners Club,
Carte Blanche, Discover, En Route, and JCB.

"""



import re
import operator

_numonlyRE=re.compile(r'[- ]')

##########################################################################
# taken from: http://www.beachnet.com/~hstiles/cardtype.html
##########################################################################
## CARD TYPE                 Prefix         Length  Check digit algorithm
## Mastercard                51-55          16      mod 10
## Visa                      4              13,16   mod 10
## Amex                      34,37          15      mod 10
## Diners Club/Carte Blanche 300-305,36,38  14      mod 10
## Discover                  6011           16      mod 10
## enRoute                   2014,2149      15      any
## JCB                       3              16      mod 10
## JCB                       2131, 1800     15      mod 10
##########################################################################


cards=(MASTERCARD,
       VISA,
       AMEX,
       DINERS_CLUB,
       CARTE_BLANCHE,
       DISCOVER,
       EN_ROUTE,
       JCB)=('MasterCard',
             'Visa',
             'American Express',
             'Diners Club',
             'Carte Blanche',
             'Discover',
             'En Route',
             'JCB')
          
card_table=[(MASTERCARD, '51', (16,)),
            (MASTERCARD, '52', (16,)),
            (MASTERCARD, '53', (16,)),
            (MASTERCARD, '54', (16,)),
            (MASTERCARD, '55', (16,)),
            (VISA, '4', (13, 16)),
            (AMEX, '34', (15,)),
            (AMEX, '37', (15,)),
            (DINERS_CLUB, '300', (14,)),
            (DINERS_CLUB, '301', (14,)),
            (DINERS_CLUB, '302', (14,)),
            (DINERS_CLUB, '303', (14,)),
            (DINERS_CLUB, '304', (14,)),
            (DINERS_CLUB, '305', (14,)),
            (DINERS_CLUB, '36', (14,)),
            (DINERS_CLUB, '38', (14,)),
            (CARTE_BLANCHE, '300', (14,)),
            (CARTE_BLANCHE, '301', (14,)),
            (CARTE_BLANCHE, '302', (14,)),
            (CARTE_BLANCHE, '303', (14,)),
            (CARTE_BLANCHE, '304', (14,)),
            (CARTE_BLANCHE, '305', (14,)),
            (CARTE_BLANCHE, '36', (14,)),
            (CARTE_BLANCHE, '38', (14,)),
            (DISCOVER, '6011', (16,)),
            (EN_ROUTE, '2014', (15,)),
            (EN_ROUTE, '2149', (15,)),
            (JCB, '3', (16,)),
            (JCB, '2131', (15,)),
            (JCB, '1800', (15,))]

card_prefix_map={}
prefix_card_map={}
prefix_length_map={}
prefixes=[]

for c in cards:
    card_prefix_map[c]=[]
for ct, prefix, lengths  in card_table:
    card_prefix_map[ct].append(prefix)
    prefix_card_map[prefix]=ct
    prefix_length_map[prefix]=lengths
    prefixes.append(prefix)
prefixes=[(len(x[1]), x[1]) for x in card_table]
prefixes.sort()
prefixes.reverse()
prefixes=[x[1] for x in prefixes]

def prefix_for_ccnum(ccnum):
    for p in prefixes:
        if ccnum.startswith(p):
            return p

def type_for_prefix(prefix):
    return prefix_card_map.get(prefix)

def length_for_prefix(prefix):
    return prefix_length_map.get(prefix)


class CreditCardValidationException(Exception):
    pass

class BadCreditCardTypeException(CreditCardValidationException):
    pass

class UnknownCreditCardPrefixException(CreditCardValidationException):
    pass

class CreditCardFormatException(CreditCardValidationException):
    pass

def check_credit_card(ccnum, cctype=None):
    """
    checks the cc number for improper characters, matches against the
    credit card type, if provided, checks the length of the credit
    card number, and verifies the check digit with Luhn's formula.
    Raises a CreditCardValidationException subclass on failing any of
    these tests.  However, if cctype is specified, and it is not
    a supported credit card type, a ValueError will be raised.
    """
    cc=_numonlyRE.sub('', ccnum)
    try:
        long(cc)
    except ValueError:
        raise CreditCardValidationException, \
              "bad characters in card number: %s" % cc
    prefix=prefix_for_ccnum(cc)
    if not prefix:
        raise UnknownCreditCardPrefixException, cc
    foundtype=type_for_prefix(prefix)
    if cctype is not None:
        if cctype not in cards:
            raise ValueError, "unrecognized card type: %s" % cctype
        if foundtype!=cctype:
            raise BadCreditCardTypeException, \
                  "expected %s, found %s" % (cctype, foundtype)
    realLengths=length_for_prefix(prefix)
    if not realLengths or len(cc) not in realLengths:
        raise CreditCardFormatException, "bad length"
    cc=map(int, list(cc))
    cc.reverse()
    s=0
    for i in range(len(cc)):
       s+=reduce(operator.add, divmod((1+(i%2))*cc[i], 10))
    # apparently En Route, whatever that is, doesn't use the check bit
    if foundtype!=EN_ROUTE and (s % 10) != 0:
        raise CreditCardFormatException, "wrong check digit"

def _gen_fake(cctype,
              start=None,
              num=1,
              prefix=None,
              length=None):
    """
    generates valid test credit cards, for testing.
    This isn't particularly efficient, as it simply
    cycles through numbers in sequence and tests
    them, rather than generating the check digits from
    the rest of the number.  But I have no reason to make
    this efficient.
    """
    if prefix is None:
        prefix=card_prefix_map[cctype][0]
    elif prefix not in card_prefix_map[cctype]:
        raise ValueError, "invalid prefix for card type: %s" % prefix
    if length is None:
        length=prefix_length_map[prefix][0]
    elif length not in prefix_length_map[prefix]:
        raise ValueError, \
              "invalid length for card prefix %s: %s" % (prefix, length)
    if start is None:
        start='%s%s' % (prefix, '0' * (length-len(prefix)))
    elif not (start.startswith(prefix) and len(start)==length):
        raise ValueError, "starting value %s inconsistent with "\
              "prefix %s and length %s" % (start, prefix, length)
    
    res=[]
    while 1:
        if len(start)!=length or not start.startswith(prefix):
            break
        try:
            check_credit_card(start, cctype)
            res.append(start)
            if num and len(res)>=num:
                break
        except CreditCardFormatException:
            pass
        start=str(long(start)+1)
    return res

        
     
    
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.