Example #1
0
async def update(client: str,
                 serial_number: str,
                 background_tasks: BackgroundTasks,
                 db: Session = Depends(get_db)):
    '''
    Client notifies server of updated user data
    '''
    logger.debug('Client (' + client + ') notified server that ID (' +
                 serial_number + ') has updated')
    db_pass = crud.get_pass(db, serial_number)
    if db_pass:
        # if a pass exists for user,
        # start background pass update task
        background_tasks.add_task(utils.update_pass, db, serial_number)
        response = Response(status_code=200)
        logger.info('Pass (' + serial_number + ') updated by client (' +
                    client + ') request')
    else:
        # no matching pass found,
        # returns HTML status no matching data
        response = Response(status_code=204)
        logger.debug('Client (' + client +
                     ') notified server about update for a non-existing user')

    return response
Example #2
0
def reader_post(request: Request,
                idNum: str = Form(...),
                db: Session = Depends(get_db)):
    '''
    Returns user data on form submit
    '''
    serial_number = idNum

    user = crud.get_pass(db, serial_number)
    response = templates.TemplateResponse('reader.html', \
        {'request': request, 'name': user.name, 'id_num': user.serial_number, 'photo_URL': user.photo_URL})

    return response
Example #3
0
def send_passes(request: Request,
                pass_type: str,
                serial_number: str,
                db: Session = Depends(get_db)):
    '''
    Getting the Latest Version of a Pass
    '''

    auth_token = str(request.headers.get('Authorization')).replace(
        'ApplePass ', '')
    if_modified_since = request.headers.get('if-modified-since')

    logger.debug('Device asked for latest version of pass (' + serial_number +
                 ') with authorization (' + auth_token + ')')

    db_pass = crud.get_pass(db, serial_number, auth_token)
    if db_pass:
        # if pass exists and auth_token matches
        if if_modified_since:
            # if if_modified_since tag exists, convert to datetime obj to compare
            if_modified_since = datetime.strptime(if_modified_since,
                                                  '%a, %d %b %Y %H:%M:%S %Z')
            # if the pass was updated after if_modified_since,
            # send the new version of the pass as a response
            if db_pass.last_update > if_modified_since:
                # force update on manual database change ->
                # crud.force_pass_update(db, db_pass.serial_number)
                response = utils.get_pass_file(db, db_pass.serial_number)
                logger.debug('Updated pass (' + serial_number +
                             ') returned to device.')
            else:
                # if the pass has not changed, return HTTP status code 304
                response = Response(status_code=304)
                logger.debug('Pass (' + serial_number + ') has not changed.')
        else:
            # if device asks for pass unconditionally,
            # respond with the current pass file
            response = utils.get_pass_file(db, db_pass.serial_number)
            logger.debug('Pass (' + serial_number +
                         ') returned unconditionally')
    else:
        # if the request is not authorized, returns HTTP status 401
        response = Response(status_code=401)
        logger.debug('Pass (' + serial_number + ') not authorized (' +
                     auth_token + ')')

    return response
Example #4
0
def delete(request: Request,
           device_id: str,
           pass_type: str,
           serial_number: str,
           db: Session = Depends(get_db)):
    '''
    Unregistering a Device
    '''

    auth_token = str(request.headers.get('Authorization')).replace(
        'ApplePass ', '')

    logger.debug('Device (' + device_id + ') deleted pass (' + serial_number +
                 ') with authorization (' + auth_token + ')')

    db_pass = crud.get_pass(db, serial_number, auth_token)
    if db_pass:
        # if pass exists and auth_token matches,
        # delete device registration for pass
        crud.delete_registration(db, device_id, serial_number)
        if not crud.get_registrations_by_device(db, device_id):
            # if not more passes exist for device,
            # delete device and push_token from device table
            crud.delete_device(db, device_id)
        # if disassociation succeeds, returns HTTP status 200
        response = Response(status_code=200)
        logger.info('Pass (' + serial_number + ') deleted from device (' +
                    device_id + ') ')
    else:
        if config.DEBUG:
            # if in debug mode, force delete
            response = Response(status_code=200)
            logger.debug('Delete request from device (' + device_id +
                         ') not authorized (' + auth_token +
                         ') but allowed (DEBUG)')
        else:
            # if the request is not authorized, returns HTTP status 401
            response = Response(status_code=401)
            logger.debug('Delete request from device (' + device_id +
                         ') not authorized (' + auth_token + ')')

    return response
Example #5
0
def register(request: Request,
             body: dict,
             device_id: str,
             pass_type: str,
             serial_number: str,
             db: Session = Depends(get_db)):
    '''
    Registering a Device to Receive Push Notifications for a Pass
    '''

    auth_token = str(request.headers.get('Authorization')).replace(
        'ApplePass ', '')
    push_token = str(body['pushToken'])

    logger.debug('Pass registration request from device (' + device_id + ')')
    if crud.get_pass(db, serial_number, auth_token):
        # if pass exists in database with same serial number & matching auth_token
        if not crud.get_device(db, device_id):
            # if no device with same device_id exists
            crud.add_device(db, device_id, push_token)
        if not crud.get_registration(db, device_id, serial_number):
            # if the device is not already registered
            # for a pass with same serial_number
            crud.add_registration(db, device_id, serial_number)
            # if registration succeeds, returns HTTP status 201.
            response = Response(status_code=201)
            logger.info('New user registered (' + serial_number + ')')
        else:
            # if the serial number is already registered for
            # this device, returns HTTP status 200.
            response = Response(status_code=200)
            logger.debug('Existing user registered (' + serial_number + ')')
    else:
        # if the request is not authorized, returns HTTP status 401
        response = Response(status_code=401)
        logger.debug('Pass registration request from device (' + device_id +
                     ') not authorized (' + auth_token + ')')

    return response
Example #6
0
    def __init__(self, db: Session, serial_number: str):
        # parse User data into reusable variables
        user_pass = crud.get_pass(db, serial_number)

        # Add user photo with different device resolution support
        response = requests.get(user_pass.photo_URL)
        img = Image.open(BytesIO(response.content))
        img = img.resize((113, 150), Image.ANTIALIAS)
        hero_image = Image.new(img.mode, (600, 200), (128, 20, 41))
        hero_image.paste(img, (450, 25))

        draw = ImageDraw.Draw(hero_image)
        font = ImageFont.truetype("include/google/Roboto-Regular.ttf", 34)
        draw.text((37, 84), user_pass.name, (255, 255, 255), font=font)

        hero_image.save('static/heroImg/' + serial_number + '.png')

        objectUid = str(services.VerticalType.LOYALTY).split(
            '.')[1] + '_OBJECT_' + str(serial_number)
        # check Reference API for format of "id" (https://developers.google.com/pay/passes/reference/v1/).
        objectId = '%s.%s' % (config.ISSUER_ID, objectUid)
        self.objectJwt = services.makeSkinnyJwt(services.VerticalType.LOYALTY,
                                                config.CLASS_ID, objectId,
                                                user_pass)
Example #7
0
    def __init__(self, db: Session, serial_number: str):
        # parse User data into reusable variables
        user_pass = crud.get_pass(db, serial_number)

        passinfo = Generic()
        passinfo.addPrimaryField('name', user_pass.name)
        passinfo.addSecondaryField('cash',
                                   '$' + str(user_pass.eagle_bucks),
                                   'Eagle Bucks',
                                   'You have %@ Eagle Bucks remaining.',
                                   textAlignment=Alignment.LEFT)
        passinfo.addSecondaryField('meals',
                                   user_pass.meals_remaining,
                                   'Meals Remaining',
                                   'You have %@ meal swipes remaining.',
                                   textAlignment=Alignment.CENTER)
        passinfo.addSecondaryField('ethos',
                                   user_pass.kudos_earned + "/" +
                                   user_pass.kudos_required,
                                   'Kudos',
                                   'You have %@ Kudos of your Semester Goal.',
                                   textAlignment=Alignment.RIGHT)
        passinfo.addBackField('pin', user_pass.id_pin, 'ID Pin')
        if user_pass.print_balance:
            passinfo.addBackField('print', user_pass.print_balance,
                                  'Print Balance',
                                  'Your print balance is now %@.')
        if user_pass.mailbox:
            passinfo.addBackField('boxnumber', user_pass.mailbox,
                                  'Mailbox Number')
        passinfo.addBackField('info', 'Please note that Automatic Updates must be turned on (default) to use the ID.\n\n' \
            + 'Report Feedback:\nhttps://forms.gle/6bAWYccfs9KsNAdP8\n\n' \
            + 'Created by the MOBIL-ID Team:\nAndrew Siemer, Jacob Button, Kyla Tarpey & Zach Jones\n')
        if config.DEBUG:
            passinfo.addBackField('hash', user_pass.pass_hash, 'Pass Hash')

        passfile = Pass(passinfo, \
            passTypeIdentifier=user_pass.pass_type , \
            organizationName='Oklahoma Chrisitian University' , \
            teamIdentifier=config.TEAM_IDENTIFIER)

        passfile.sharingProhibited = True
        passfile.webServiceURL = config.WEB_SERVICE_URL
        passfile.authenticationToken = user_pass.auth_token
        passfile.description = 'OC ID'
        passfile.associatedStoreIdentifiers = [
            306012905,
        ]
        passfile.foregroundColor = 'rgb(255, 255, 255)'
        passfile.backgroundColor = 'rgb(128, 20, 41)'
        passfile.labelColor = 'rgb(255, 255, 255)'
        passfile.serialNumber = user_pass.serial_number
        passfile.barcode = Barcode(user_pass.pass_hash, BarcodeFormat.QR,
                                   user_pass.serial_number)
        passfile.locations = list()
        passfile.locations.append(
            Location(35.611219,
                     -97.467255,
                     relevantText='Welcome to Garvey! Tap to scan your ID.',
                     maxDistance=20))
        passfile.locations.append(
            Location(
                35.6115,
                -97.4695,
                relevantText='Welcome to the Branch! Tap to scan your ID.',
                maxDistance=20))
        passfile.locations.append(
            Location(35.61201,
                     -97.46850,
                     relevantText='Welcome to the Brew! Tap to scan your ID.',
                     maxDistance=20))
        # passfile.locations.append(Location(35.613257, -97.467833, relevantText='Welcome to the PEC! Tap to scan your ID.', maxDistance=20))
        passfile.ibeacons = list()
        passfile.ibeacons.append(
            IBeacon('1F234454-CF6D-4A0F-ADF2-F4911BA9FFA9', 1, 1,
                    'Tap to scan your ID.'))

        # Including the icon and logo is necessary for the passbook to be valid.
        passfile.addFile('icon.png', open('base.pass/icon.png', 'rb'))
        passfile.addFile('*****@*****.**', open('base.pass/[email protected]', 'rb'))
        passfile.addFile('*****@*****.**', open('base.pass/[email protected]', 'rb'))
        passfile.addFile('logo.png', open('base.pass/logo.png', 'rb'))
        passfile.addFile('*****@*****.**', open('base.pass/[email protected]', 'rb'))
        passfile.addFile('*****@*****.**', open('base.pass/[email protected]', 'rb'))

        try:
            # Add user photo with different device resolution support
            response = requests.get(user_pass.photo_URL)
            img = Image.open(BytesIO(response.content))

            # Add 3x resolution thumbnail
            img = img.resize((204, 270))
            img_byte = BytesIO()
            img.save(img_byte, format='PNG')
            passfile.addFile('*****@*****.**', img_bytes=img_byte.getvalue())

            # Add 2x resolution thumbnail
            img = img.resize((136, 180))
            img_byte = BytesIO()
            img.save(img_byte, format='PNG')
            passfile.addFile('*****@*****.**', img_bytes=img_byte.getvalue())

            # Add 1x resolution thumbnail
            img = img.resize((68, 90))
            img_byte = BytesIO()
            img.save(img_byte, format='PNG')
            passfile.addFile('thumbnail.png', img_bytes=img_byte.getvalue())
        except:
            # Include default identification photo
            passfile.addFile('thumbnail.png',
                             open('base.pass/thumbnail.png', 'rb'))
            passfile.addFile('*****@*****.**',
                             open('base.pass/[email protected]', 'rb'))
            passfile.addFile('*****@*****.**',
                             open('base.pass/[email protected]', 'rb'))

        # Create and output the Passbook file (.pkpass)
        passfile.create(config.PASS_TYPE_CERTIFICATE_PATH,
                        config.PASS_TYPE_CERTIFICATE_PATH,
                        config.WWDR_CERTIFICATE_PATH, config.PEM_PASSWORD,
                        'passes/' + user_pass.serial_number + '.pkpass')
Example #8
0
def submit(request: Request,
           idNum: str = Form(...),
           idPin: str = Form(...),
           db: Session = Depends(get_db)):
    '''
    Login Sumbitted, Validates User & Creates Pass
    '''

    # get user data from form
    entered_id_num = idNum
    entered_id_pin = idPin

    logger.debug('Registration submitted for ID (' + entered_id_num +
                 ') with Pin (' + entered_id_pin + ')')
    if entered_id_num in config.WHITELIST or not config.WHITELIST:
        if utils.input_validate(entered_id_num, entered_id_pin):
            # if user form data passes server-side validation,
            # check for existing pass
            db_pass = crud.get_pass(db, entered_id_num)
            if not db_pass:
                # if pass for user does not exist,
                # check for vaild User though OC
                user = schemas.User(entered_id_num, entered_id_pin)
                if user.is_valid():
                    # add user_pass to database
                    db_pass = crud.add_pass(db, user)
                    # create pass for given user
                    schemas.Pkpass(db, db_pass.serial_number)
                    google = schemas.JWT(db, db_pass.serial_number)

                    # respond with success page with Add to Apple Wallet button
                    response = templates.TemplateResponse('success.html', \
                        {'request': request, 'pass_hash': db_pass.pass_hash, 'jwt': google.get_link()})
                    logger.info('Pass created for ID (' + entered_id_num + ')')
                else:
                    # user not valid through OC,
                    # return login page with feedback
                    del user
                    response = templates.TemplateResponse('index.html', \
                        {'request': request, 'feedback': 'The ID Number and ID Card Pin Number entered do not match. Please try again.', 'entered_id': entered_id_num})
                    logger.debug('Registration unsuccessful for ID (' +
                                 entered_id_num + ') with Pin (' +
                                 entered_id_pin + ')')
            elif db_pass.id_pin == entered_id_pin:
                google = schemas.JWT(db, db_pass.serial_number)

                # pass for user already exists and login is correct,
                # respond with success page with Add to Apple Wallet button
                response = templates.TemplateResponse('success.html', \
                    {'request': request, 'pass_hash': db_pass.pass_hash, 'jwt': google.get_link()})
                logger.info('Existing user successful request for ID (' +
                            entered_id_num + ')')
            else:
                # pass for user already exists but login is incorrect,
                # user not valid through server quick validation
                response = templates.TemplateResponse('index.html', \
                    {'request': request, 'feedback': 'The ID Number and ID Card Pin Number entered do not match. Please try again.', 'entered_id': entered_id_num})
                logger.debug('Registration unsuccessful for ID (' +
                             entered_id_num + ') with Pin (' + entered_id_pin +
                             ')')
        else:
            # user not valid through server quick validation
            response = templates.TemplateResponse('index.html', \
                {'request': request, 'feedback': 'The ID Number and ID Card Pin Number entered do not match. Please try again.', 'entered_id': entered_id_num})
            logger.debug('Registration unsuccessful for ID (' +
                         entered_id_num + ') with Pin (' + entered_id_pin +
                         ')')
    else:
        # entered ID num is not on whitelist
        response = templates.TemplateResponse('index.html', \
            {'request': request, 'beta': 'The beta-testing program is currently invite-only.'})
        logger.debug('Registration unsuccessful for ID (' + entered_id_num +
                     ') with Pin (' + entered_id_pin + ')')

    return response