def fconnect(): """Handle facebook OAuth login GET /auth/fconnect If user does not exists create a new user. """ # userinfo has email, username, and access token userinfo = json.loads(request.data) user_access_token = userinfo.get('access_token') # To verify user's access token, we need to get our app token first. url = ('https://graph.facebook.com/oauth/access_token?' 'client_id={}&client_secret={}' '&grant_type=client_credentials'.format( config.FACEBOOK_CLIENT_ID, config.FACEBOOK_CLIENT_SECRET)) try: h = httplib2.Http() result = h.request(url, 'GET')[1] app_token = re.search(r'(access_token=)(.+?$)', result).group(2) print app_token # Using app token, we can verify user's access token url = ('https://graph.facebook.com/debug_token' '?input_token={}&access_token={}'.format( user_access_token, app_token)) h = httplib2.Http() result = json.loads(h.request(url, 'GET')[1]) user_data = result.get("data") # If the user's token is valid to the app token, # Facecook api returns the variable 'is_valid' with True if not user_data.get("is_valid"): response = make_response( json.dumps("User access token is not valid"), 401) flash("Facebook connection Error.") response.headers['Content-Type'] = 'application/json' return response email = userinfo.get('email') user = User.get_by_email(session, email.strip()) # Create and store a new user if there is no user exist if not user: user = User(email=email) session.add(user) session.commit() expire_time, token = generate_token(user) flash("Successfully logged in with Facebook") response = make_response(redirect(url_for('basic.showMain')), 200) response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) return response except: response = make_response(json.dumps("User access token is not valid"), 401) flash("Facebook connection Error.") response.headers['Content-Type'] = 'application/json' return response
def editItem(category_id, item_id): item = getItemInfo(item_id) category = getCategoryInfo(category_id) form = EditItem(request.form) if request.files: form.picture.data = request.files['picture'] if request.method == 'POST' and form.validate(): if form.title.data: item.title = ' '.join( name.capitalize() for name in form.title.data.split() ) if form.description.data: item.description = form.description.data if form.picture.data: item.picture = saveItemPicture(form.picture.data, item.id) session.add(item) session.commit() flash("Succesfully edited item %s" % item.title) return redirect( url_for( 'showItem', category_id=category_id, item_id=item.id ) ) return render_template( 'edititem.html', category=category, item=item, form=form )
def newCategory(): # Create the WTForm form = CategoryForm(request.form) if request.method == 'POST' and form.validate(): # If it's a post and the form is valid, we format the title and Create # the new category new_category = Category( title=' '.join( name.capitalize() for name in form.title.data.split() ) ) session.add(new_category) session.commit() flash("New category %s successfully created!" % new_category.title) return redirect(url_for('index')) else: return render_template('newcategory.html', form=form)
def createUser(login_session): ''' Method for creating an user from the login_session This method should be called after the successful completion of the oauth flow and consequent acquisition of the required user info: - username - email - picture ''' # We are presuming that the username and email will be formatted correctly new_user = User( name=login_session['username'], email=login_session['email'], picture=login_session['picture'] ) session.add(new_user) session.commit() user = getUserByEmail(login_session['email']) return user.id
def newItem(category_id): category = getCategoryInfo(category_id) # create the WTForm form = NewItem(request.form) # The picture is mandatory, but we need to pass it separately to WTForm as # the constructor only receives the form itself.. if request.files: form.picture.data = request.files['picture'] if request.method == 'POST' and form.validate(): # After validating the form, we build the item object with the # formatted title and with an empty string for the picture. # We need to do this because we will use the item id to save the # picture. new_item = Item( title=' '.join( name.capitalize() for name in form.title.data.split() ), description=form.description.data, picture='', category_id=category.id, user_id=login_session['user_id'] ) session.add(new_item) session.commit() # Now that we have the new item id, we save the picture and update the # item with the picture path path = saveItemPicture(form.picture.data, new_item.id) new_item.picture = path session.add(new_item) session.commit() flash("Added %s to %s!" % (new_item.title, category.title)) return redirect(url_for('showCategory', category_id=category.id)) else: return render_template( 'newitem.html', category=category, form=form )
def editItem(category_id, item_id): """ GET /category/category id/item/item id/edit: Render an edit item form page POST /category/category id/item/item id/edit: Update the selected item's attributes Fields: title (required) description category (required) """ token = request.cookies.get('token') expire_time = request.cookies.get('expire_time') # Only authorized user can see an edit item page if not token: flash("You are not authorized.") return redirect(url_for('basic.showMain')) if request.method == "GET": # Only authorized user can see an edit item page user_data = validate_token(token, expire_time) if not user_data: flash("You are not authorized.") return redirect(url_for('basic.showMain')) # Only authorized user can see an edit item page # Authorized user id must be the same as # the user's id who created the item before. if not User.is_authorized(session, user_data.get("id"), item_id): flash("You are not authorized.") return redirect(url_for('basic.showMain')) categories = Category.get_all(session) item = Item.get_by_id(session, item_id) return render_template('edit_item.html', categories=categories, item=item) if request.method == "POST": # When user send POST request, # we get a token again from HTTP header, not from cookie token = request.headers.get('Authorization') # Only authorized user can edit this item user_data = validate_token(token, expire_time) if not user_data: response = make_response( json.dumps({ "message": "You are not authorized", "redirect": url_for('basic.showItemDetail', category_id=category_id, item_id=item_id) }), 401 ) response.headers['Content-Type'] = 'application/json' return response item = Item.get_by_id(session, item_id) title = request.form.get('title') description = request.form.get('description') new_category_id = request.form.get('category') # In the form in HTML title field is required. # No title means the user use another way to send POST request if not title: response = make_response( json.dumps({ "message": "Please use the proper way", "redirect": url_for('basic.showItemDetail', category_id=category_id, item_id=item_id) }), 401 ) response.headers['Content-Type'] = 'application/json' return response # Only authorized user can edit item # Authorized user id must be the same as # the user's id who created the item before. user = User.get_by_id(session, user_data.get("id")) if not User.is_authorized(session, user.id, item_id): response = make_response( json.dumps({ "message": "You are not authorized", "redirect": url_for('basic.showItemDetail', category_id=item.category_id, item_id=item_id) }), 401 ) response.headers['Content-Type'] = 'application/json' return response item.title = title item.description = description item.category_id = new_category_id session.add(item) session.commit() response = make_response( json.dumps({ "message": "The item was successfully edited.", "redirect": url_for('basic.showItemDetail', category_id=category_id, item_id=item.id) }), 200 ) response.headers['Content-Type'] = 'application/json' return response
def addItem(): """ GET /items: Render a create item form page POST /items: Create a new item and store it in database. Fields: title (required) description category (required) Created date are default saved as timestamp """ token = request.cookies.get('token') expire_time = request.cookies.get('expire_time') # Only authenticated user can add a new item if not token: flash("Please login.") return redirect(url_for('auth.login')) if request.method == "GET": user_data = validate_token(token, expire_time) categories = Category.get_all(session) return render_template('add_item.html', categories=categories, user=user_data) if request.method == "POST": # When user send POST request, # we get a token again from HTTP header, not from cookie token = request.headers.get('Authorization') # Only authenticated user can add a new item user_data = validate_token(token, expire_time) if not user_data: response = make_response( json.dumps({ "message": "Please login", "redirect": url_for('auth.login') }), 401 ) response.headers['Content-Type'] = 'application/json' return response # Get title, description, and category_id from the form. title = request.form.get('title') description = request.form.get('description') category_id = request.form.get('category') # In the form in HTML title field is required. # No title means the user use another way to send POST request if not title: response = make_response( json.dumps({ "message": "Please use the proper way", "redirect": url_for('basic.addItem') }), 401 ) response.headers['Content-Type'] = 'application/json' return response # Create a new item row with the fields user has inputted item = Item(title=title, description=description, category_id=category_id, user_id=user_data.get("id")) session.add(item) session.commit() # Redirect to the detail page, so user can check their input. response = make_response( json.dumps({ "message": "The item was successfully created.", "redirect": url_for('basic.showItemDetail', category_id=category_id, item_id=item.id) }), 200 ) response.headers['Content-Type'] = 'application/json' return response
def gconnect(): """Handle Google OAuth login. GET /auth/gconnect If user does not exists create a new user. """ # Check csrf token cookie_csrf_token = request.cookies.get('csrf_token') if request.args.get('_csrf_token') != cookie_csrf_token: flash("Please use proper authentication.") response = make_response(json.dumps('Fail to connect'), 401) response.headers['Content-Type'] = 'application/json' return response # code is a return value from front-end google + oauth API code = request.data try: # Create oauth login flow based on client_secret.json # Please make sure that you have downloaded and placed # client_secret.json properly. Please read README file. oauth_flow = flow_from_clientsecrets('settings/client_secret.json', scope='') oauth_flow.redirect_uri = 'postmessage' credentials = oauth_flow.step2_exchange(code) except FlowExchangeError: flash("Google plus connection Error.") response = make_response(json.dumps('Fail to upgrade'), 401) response.headers['Content-Type'] = 'application/json' return response # Get an access_token from Goolge OAuth provider access_token = credentials.access_token url = ('https://www.googleapis.' 'com/oauth2/v1/tokeninfo?access_token=%s' % access_token) h = httplib2.Http() result = json.loads(h.request(url, 'GET')[1]) if result.get('error') is not None: flash("Google plus connection Error.") response = make_response(json.dumps(result.get('error')), 500) response.headers['Content-Type'] = 'application/json' return response # Get user id stored in Google gplus_id = credentials.id_token['sub'] if result['user_id'] != gplus_id: flash("Google plus connection Error.") response = make_response(json.dumps("Token's user ID doesn't match"), 401) response.headers['Content-Type'] = 'application/json' return response # Make sure client id is correct if result['issued_to'] != CLIENT_ID: response = make_response(json.dumps("Token's client ID doesn't match"), 401) flash("Google plus connection Error.") response.headers['Content-Type'] = 'application/json' return response # Retrieve user info. stored in Google userinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo' params = {'access_token': credentials.access_token, 'alt': 'json'} answer = requests.get(userinfo_url, params=params) data = json.loads(answer.text) email = data['email'] user = User.get_by_email(session, email.strip()) # If user does not exist, create a new user if not user: user = User(email=email) session.add(user) session.commit() # Generate JSON web token for user. # As long as client has non-expired and valid token, # they do not need to login again. flash("Successfully logged in with Google +") expire_time, token = generate_token(user) response = make_response(redirect(url_for('basic.showMain'))) # Store the JSON web token and Google + access token in the browser cookie. response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) response.set_cookie('gplus_token', value=access_token) return response
def signup(): """Render login page and handle login form data. Requests: GET /auth/signup POST /auth/signup """ if request.method == 'GET': csrf_token = generate_csrf_token() response = make_response( render_template('signup.html', client_id=CLIENT_ID)) # Store the csrf_token in the browser cookie. response.set_cookie('csrf_token', value=csrf_token) return response # Form fields: # email: user email, required # password: user password, required # confirm: user confirm password, required # User email, and hashed password and salt are stored when login succeed. if request.method == 'POST': # Check csrf token cookie_csrf_token = request.cookies.get('csrf_token') form_csrf_token = request.form.get('_csrf_token') # CSRF attack detected! if cookie_csrf_token != form_csrf_token: flash("Please use proper signup.") return render_template('signup.html', client_id=CLIENT_ID, csrf_token="") # Get user data from login form. email = request.form.get('email') password = request.form.get('password') confirm = request.form.get('confirm') # User must fill the email and password field. if not (email and password and confirm): flash("Please fill the form. ") return render_template('signup.html', cached_email=email) # Password field and confirm fields must be the same. if not (password == confirm): flash("Confirm password has to be the same as password") return render_template('signup.html', cached_email=email) # Find user in the database by email. user = User.get_by_email(session, email.strip()) # User already exist, remind user that. if user: if user.password: flash("Such user already exist. Please login") return render_template('signup.html', cached_email=email) # Create a new user object else: user = User(email=email.strip()) # Store encrypted password and salt in the database user.password, user.salt = encrypt_password(password) session.add(user) session.commit() # Generate JSON web token for user. # As long as client has non-expired and valid token, # they do not need to login again. expire_time, token = generate_token(user) response = make_response(redirect(url_for('basic.showMain'))) # Store the token in the browser cookie. response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) return response
def fconnect(): """Handle facebook OAuth login GET /auth/fconnect If user does not exists create a new user. """ # userinfo has email, username, and access token userinfo = json.loads(request.data) user_access_token = userinfo.get('access_token') # To verify user's access token, we need to get our app token first. url = ('https://graph.facebook.com/oauth/access_token?' 'client_id={}&client_secret={}' '&grant_type=client_credentials' .format(config.FACEBOOK_CLIENT_ID, config.FACEBOOK_CLIENT_SECRET)) try: h = httplib2.Http() result = h.request(url, 'GET')[1] app_token = re.search(r'(access_token=)(.+?$)', result).group(2) print app_token # Using app token, we can verify user's access token url = ('https://graph.facebook.com/debug_token' '?input_token={}&access_token={}' .format(user_access_token, app_token)) h = httplib2.Http() result = json.loads(h.request(url, 'GET')[1]) user_data = result.get("data") # If the user's token is valid to the app token, # Facecook api returns the variable 'is_valid' with True if not user_data.get("is_valid"): response = make_response( json.dumps("User access token is not valid"), 401 ) flash("Facebook connection Error.") response.headers['Content-Type'] = 'application/json' return response email = userinfo.get('email') user = User.get_by_email(session, email.strip()) # Create and store a new user if there is no user exist if not user: user = User(email=email) session.add(user) session.commit() expire_time, token = generate_token(user) flash("Successfully logged in with Facebook") response = make_response( redirect(url_for('basic.showMain')), 200 ) response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) return response except: response = make_response( json.dumps("User access token is not valid"), 401 ) flash("Facebook connection Error.") response.headers['Content-Type'] = 'application/json' return response
def gconnect(): """Handle Google OAuth login. GET /auth/gconnect If user does not exists create a new user. """ # Check csrf token cookie_csrf_token = request.cookies.get('csrf_token') if request.args.get('_csrf_token') != cookie_csrf_token: flash("Please use proper authentication.") response = make_response(json.dumps('Fail to connect'), 401) response.headers['Content-Type'] = 'application/json' return response # code is a return value from front-end google + oauth API code = request.data try: # Create oauth login flow based on client_secret.json # Please make sure that you have downloaded and placed # client_secret.json properly. Please read README file. oauth_flow = flow_from_clientsecrets('settings/client_secret.json', scope='') oauth_flow.redirect_uri = 'postmessage' credentials = oauth_flow.step2_exchange(code) except FlowExchangeError: flash("Google plus connection Error.") response = make_response(json.dumps('Fail to upgrade'), 401) response.headers['Content-Type'] = 'application/json' return response # Get an access_token from Goolge OAuth provider access_token = credentials.access_token url = ('https://www.googleapis.' 'com/oauth2/v1/tokeninfo?access_token=%s' % access_token) h = httplib2.Http() result = json.loads(h.request(url, 'GET')[1]) if result.get('error') is not None: flash("Google plus connection Error.") response = make_response( json.dumps(result.get('error')), 500 ) response.headers['Content-Type'] = 'application/json' return response # Get user id stored in Google gplus_id = credentials.id_token['sub'] if result['user_id'] != gplus_id: flash("Google plus connection Error.") response = make_response( json.dumps("Token's user ID doesn't match"), 401 ) response.headers['Content-Type'] = 'application/json' return response # Make sure client id is correct if result['issued_to'] != CLIENT_ID: response = make_response( json.dumps("Token's client ID doesn't match"), 401 ) flash("Google plus connection Error.") response.headers['Content-Type'] = 'application/json' return response # Retrieve user info. stored in Google userinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo' params = {'access_token': credentials.access_token, 'alt': 'json'} answer = requests.get(userinfo_url, params=params) data = json.loads(answer.text) email = data['email'] user = User.get_by_email(session, email.strip()) # If user does not exist, create a new user if not user: user = User(email=email) session.add(user) session.commit() # Generate JSON web token for user. # As long as client has non-expired and valid token, # they do not need to login again. flash("Successfully logged in with Google +") expire_time, token = generate_token(user) response = make_response(redirect(url_for('basic.showMain'))) # Store the JSON web token and Google + access token in the browser cookie. response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) response.set_cookie('gplus_token', value=access_token) return response
def signup(): """Render login page and handle login form data. Requests: GET /auth/signup POST /auth/signup """ if request.method == 'GET': csrf_token = generate_csrf_token() response = make_response( render_template('signup.html', client_id=CLIENT_ID) ) # Store the csrf_token in the browser cookie. response.set_cookie('csrf_token', value=csrf_token) return response # Form fields: # email: user email, required # password: user password, required # confirm: user confirm password, required # User email, and hashed password and salt are stored when login succeed. if request.method == 'POST': # Check csrf token cookie_csrf_token = request.cookies.get('csrf_token') form_csrf_token = request.form.get('_csrf_token') # CSRF attack detected! if cookie_csrf_token != form_csrf_token: flash("Please use proper signup.") return render_template('signup.html', client_id=CLIENT_ID, csrf_token="") # Get user data from login form. email = request.form.get('email') password = request.form.get('password') confirm = request.form.get('confirm') # User must fill the email and password field. if not (email and password and confirm): flash("Please fill the form. ") return render_template('signup.html', cached_email=email) # Password field and confirm fields must be the same. if not (password == confirm): flash("Confirm password has to be the same as password") return render_template('signup.html', cached_email=email) # Find user in the database by email. user = User.get_by_email(session, email.strip()) # User already exist, remind user that. if user: if user.password: flash("Such user already exist. Please login") return render_template('signup.html', cached_email=email) # Create a new user object else: user = User(email=email.strip()) # Store encrypted password and salt in the database user.password, user.salt = encrypt_password(password) session.add(user) session.commit() # Generate JSON web token for user. # As long as client has non-expired and valid token, # they do not need to login again. expire_time, token = generate_token(user) response = make_response(redirect(url_for('basic.showMain'))) # Store the token in the browser cookie. response.set_cookie('token', value=token) response.set_cookie('expire_time', value=str(expire_time)) return response
def editItem(category_id, item_id): """ GET /category/category id/item/item id/edit: Render an edit item form page POST /category/category id/item/item id/edit: Update the selected item's attributes Fields: title (required) description category (required) """ token = request.cookies.get("token") expire_time = request.cookies.get("expire_time") # Only authorized user can see an edit item page if not token: flash("You are not authorized.") return redirect(url_for("basic.showMain")) if request.method == "GET": # Only authorized user can see an edit item page user_data = validate_token(token, expire_time) if not user_data: flash("You are not authorized.") return redirect(url_for("basic.showMain")) # Only authorized user can see an edit item page # Authorized user id must be the same as # the user's id who created the item before. if not User.is_authorized(session, user_data.get("id"), item_id): flash("You are not authorized.") return redirect(url_for("basic.showMain")) categories = Category.get_all(session) item = Item.get_by_id(session, item_id) return render_template("edit_item.html", categories=categories, item=item) if request.method == "POST": # When user send POST request, # we get a token again from HTTP header, not from cookie token = request.headers.get("Authorization") # Only authorized user can edit this item user_data = validate_token(token, expire_time) if not user_data: response = make_response( json.dumps( { "message": "You are not authorized", "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item_id), } ), 401, ) response.headers["Content-Type"] = "application/json" return response item = Item.get_by_id(session, item_id) title = request.form.get("title") description = request.form.get("description") new_category_id = request.form.get("category") # In the form in HTML title field is required. # No title means the user use another way to send POST request if not title: response = make_response( json.dumps( { "message": "Please use the proper way", "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item_id), } ), 401, ) response.headers["Content-Type"] = "application/json" return response # Only authorized user can edit item # Authorized user id must be the same as # the user's id who created the item before. user = User.get_by_id(session, user_data.get("id")) if not User.is_authorized(session, user.id, item_id): response = make_response( json.dumps( { "message": "You are not authorized", "redirect": url_for("basic.showItemDetail", category_id=item.category_id, item_id=item_id), } ), 401, ) response.headers["Content-Type"] = "application/json" return response item.title = title item.description = description item.category_id = new_category_id session.add(item) session.commit() response = make_response( json.dumps( { "message": "The item was successfully edited.", "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item.id), } ), 200, ) response.headers["Content-Type"] = "application/json" return response
def addItem(): """ GET /items: Render a create item form page POST /items: Create a new item and store it in database. Fields: title (required) description category (required) Created date are default saved as timestamp """ token = request.cookies.get("token") expire_time = request.cookies.get("expire_time") # Only authenticated user can add a new item if not token: flash("Please login.") return redirect(url_for("auth.login")) if request.method == "GET": user_data = validate_token(token, expire_time) categories = Category.get_all(session) return render_template("add_item.html", categories=categories, user=user_data) if request.method == "POST": # When user send POST request, # we get a token again from HTTP header, not from cookie token = request.headers.get("Authorization") # Only authenticated user can add a new item user_data = validate_token(token, expire_time) if not user_data: response = make_response(json.dumps({"message": "Please login", "redirect": url_for("auth.login")}), 401) response.headers["Content-Type"] = "application/json" return response # Get title, description, and category_id from the form. title = request.form.get("title") description = request.form.get("description") category_id = request.form.get("category") # In the form in HTML title field is required. # No title means the user use another way to send POST request if not title: response = make_response( json.dumps({"message": "Please use the proper way", "redirect": url_for("basic.addItem")}), 401 ) response.headers["Content-Type"] = "application/json" return response # Create a new item row with the fields user has inputted item = Item(title=title, description=description, category_id=category_id, user_id=user_data.get("id")) session.add(item) session.commit() # Redirect to the detail page, so user can check their input. response = make_response( json.dumps( { "message": "The item was successfully created.", "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item.id), } ), 200, ) response.headers["Content-Type"] = "application/json" return response