Ejemplo n.º 1
0
def authenticate_request(request):
    """Authenticate a user given a Firebase token or an API key
    passed in an `Authentication: Bearer <token>` header.
    Args:
        request: An instance of `django.http.HttpRequest` or
            `rest_framework.request.Request`.
    Returns:
        claims (dict): A dictionary of the user's custom claims, including
            the user's `uid`.
    """
    claims = {}
    try:
        session_cookie = request.COOKIES.get('__session')
        print('Session cookie:', session_cookie)
        if session_cookie is None:
            session_cookie = request.session.get('__session')
            print('Session cookie (2nd try):', session_cookie)
        claims = verify_session_cookie(session_cookie, check_revoked=True)
        print('Verified:', claims.get('email'))
    except:
        try:
            authorization = request.META['HTTP_AUTHORIZATION']
            key = authorization.split(' ').pop()
            claims = get_user_from_api_key(key)
            print('Verified by auth header:', claims.get('email'))
        except:
            claims = {}
    return claims
Ejemplo n.º 2
0
def logout(request, *args, **argv):  #pylint: disable=unused-argument
    """Functional view to remove a user session.
    FIXME: Does not appear to delete the user's session!
    """
    try:
        print('Signing user out.')
        session_cookie = request.COOKIES.get('__session')
        if session_cookie is None:
            session_cookie = request.session['__session']
        claims = verify_session_cookie(session_cookie)
        uid = claims['uid']
        create_log(ref=f'users/{uid}/logs',
                   claims=claims,
                   action='Signed out.',
                   log_type='auth',
                   key='logout')
        update_document(f'users/{uid}', {'signed_in': False})
        print('Updated user as signed-out in Firestore:', uid)
        revoke_refresh_tokens(claims['sub'])
        # request.session['__session'] = ''
        response = HttpResponse(status=205)
        # response = JsonResponse({'success': True}, status=205)
        response['Set-Cookie'] = '__session=None; Path=/'
        response['Cache-Control'] = 'public, max-age=300, s-maxage=900'
        return response
    except:
        # request.session['__session'] = ''
        response = HttpResponse(status=205)
        # response = JsonResponse({'success': True}, status=205)
        response['Set-Cookie'] = '__session=None; Path=/'
        response['Cache-Control'] = 'public, max-age=300, s-maxage=900'
        return response
Ejemplo n.º 3
0
def download_csv_data(request):
    """Download posted data as a CSV file.
    TODO: Pull requested data again (by ID) instead of using posted data.
    TODO: Limit the size / rate of downloads (tie to account usage / billing).
    """
    session_cookie = request.COOKIES.get('__session')
    claims = verify_session_cookie(session_cookie)
    if not claims:
        return HttpResponse(status=401)
    data = loads(request.body.decode('utf-8'))['data']
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="download.csv"'
    writer = csv.writer(response)
    writer.writerow(list(data[0].keys()))
    for item in data:
        writer.writerow(list(item.values()))
    return response
Ejemplo n.º 4
0
def verify_session(request):
    """Verifies that the user has authenticated with a Firebase ID token.
    If the session cookie is unavailable, then force the user to login.
    Verify the session cookie. In this case an additional check is added to detect
    if the user's Firebase session was revoked, user deleted/disabled, etc.
    If the session cookie is invalid, expired or revoked, then force the user to login.
    Args:
        request: An instance of `django.http.HttpRequest` or
            `rest_framework.request.Request`.
    Returns:
        claims (dict): A dictionary of the user's custom claims, including
            the user's `uid`.
    """
    # try:
    # session_cookie = request.COOKIES.get('__session')
    session_cookie = request.session.get('__session')
    print('Session cookie:', session_cookie)
    if session_cookie is None:
        session_cookie = request.COOKIES.get('__session')
        print('Session cookie (2nd try):', session_cookie)
        # session_cookie = request.session.get('__session')
    claims = verify_session_cookie(session_cookie, check_revoked=True)
    print('Verified by auth header:', claims.get('email'))
    return claims
Ejemplo n.º 5
0
def import_data(request):
    """Import data from an Excel worksheet for a given data model.
    TODO: Limit the size / rate of downloads (tie to account usage / billing).
    Optional: Handle .csv imports.
    Optional: Submit form without refresh.
    """
    # Authenticate the user.
    session_cookie = request.COOKIES.get('__session')
    claims = verify_session_cookie(session_cookie)
    if not claims:
        return HttpResponse(status=401)

    # Get the import parameters and file, validating the file.
    # Also, authorize that the user is part of the organization.
    model = request.GET.get('model')
    org_id = request.GET.get('organization_id')
    excel_file = request.FILES['excel_file']
    ext = excel_file.name.split('.').pop()
    if excel_file.size >= 1024 * 1000 * 500:
        return JsonResponse({
            'error': True,
            'message': 'File too large.'
        },
                            status=406)
    if ext not in ['csv', 'xlsx', 'xlsm']:
        return JsonResponse(
            {
                'error': True,
                'message': 'Expected a .csv, .xlsx, or .xlsm file.'
            },
            status=406)
    if org_id not in claims.get('team', []):
        return HttpResponse(
            {
                'error': True,
                'message': 'You are not a member of this organization.'
            },
            status=403)

    # Read the data from Excel.
    data = read_worksheet(excel_file)

    # Get singular from data models, to identify the ID.
    data_model = get_document(f'organizations/{org_id}/data_models/{model}')
    model_singular = data_model['singular']

    # Clean data according to data type.
    # Optional: Add more validation / data cleaning by type.
    for field in data_model['fields']:
        key = field['key']
        data_type = field.get('type', 'text')
        if data_type == 'text' or data_type == 'textarea':
            data[key].replace(['0', '0.0', 0], '', inplace=True)

    # Save imported data to Firestore (FIXME: in reverse order for user sanity).
    updated_at = datetime.now().isoformat()
    for key, row in data.iterrows():
        # data = data.replace({np.nan: None})
        # for idx in reversed(data.index):
        # row = data.loc[idx]
        doc_id = row[f'{model_singular}_id']
        if doc_id:
            values = row.to_dict()
            values['updated_at'] = updated_at
            values['updated_by'] = claims['uid']
            update_document(f'organizations/{org_id}/{model}/{doc_id}', values)

    # Submit the form (FIXME: preferably without refreshing).
    # See: https://stackoverflow.com/questions/11647715/how-to-submit-form-without-refreshing-page-using-django-ajax-jquery
    return HttpResponseRedirect(f'/{model}')