def send_confirmmail_to_unregistered_users(items): """Send a confirmation email for external signups(email only) Args: item: The item, which was just inserted into the database """ for item in items: if 'user' not in item: event = current_app.data.find_one( 'events', None, **{current_app.config['ID_FIELD']: item['event']}) if 'title_en' in event: title = event['title_en'] else: title = event['title_de'] token = Signer(get_token_secret()).sign( str(item['_id']).encode('utf-8')) if current_app.config.get('SERVER_NAME') is None: current_app.logger.warning("SERVER_NAME is not set. E-Mail " "links will not work!") fields = { 'link': url_for('emails.on_confirm_email', token=token, _external=True), 'title': title } email_content = current_app.config['CONFIRM_EMAIL_TEXT'] % fields mail(current_app.config['API_MAIL'], # from [item['email']], # receivers list 'Registration for AMIV event %s' % title, email_content)
def on_confirm_email(token): """Email confirmation endpoint. We try to confirm the specified signup and redirect to a webpage. """ try: s = Signer(get_token_secret()) signup_id = ObjectId(s.unsign(token).decode('utf-8')) except BadSignature: return "Unknown token" patch_internal('eventsignups', {'confirmed': True}, skip_validation=True, concurrency_check=False, **{current_app.config['ID_FIELD']: signup_id}) # Now the user may be able to get accepted, so update the events waiting # list lookup = {current_app.config['ID_FIELD']: signup_id} signup = current_app.data.find_one('eventsignups', None, **lookup) update_waiting_list(signup['event']) redirect_url = current_app.config.get('EMAIL_CONFIRMED_REDIRECT') if redirect_url: return redirect(redirect_url) else: return current_app.config['CONFIRM_TEXT']
def verify_cookie(cookey): """ verify that the signature contained in the cookie corresponds to the informations sent by the app (see generate_cookie_info) """ is_correct = False debug("verify_cookie for origin: " + base64_decode(cookey)) cookie_value = request.cookies.get(cookey) if cookie_value: debug("cookie exists for this origin") s = Signer(app.secret_key) expected_cookie_content = \ generate_cookie_info(base64_decode(cookey)) expected_cookie_content = s.get_signature(expected_cookie_content) debug("verify_cookie: " + cookie_value + ", " + expected_cookie_content) if expected_cookie_content == cookie_value: debug('correct cookie') is_correct = True else: debug('incorrect cookie') return is_correct
def invitation(): code = request.args.get('code') token = request.args.get('token') if not code or not token: abort(404) if token != Invite.get_token(code): abort(400) invite = Invite.query.filter_by(code=code).first() if invite: if invite.redeemed: abort(400) if current_user.is_authenticated: logout_user() invite_id = Signer(app.config.get('CONFIRMATION_SECRET')).sign( str(invite.id)).decode('ascii') form = SignUpForm(invite=invite_id) return render_template('signup.html', form=form) else: abort(404)
def action(): if not 'action' in request.json: abort(400) s = Signer(signkey) try: action = s.unsign(request.json['action']) except: abort(403) action = action.split('.', 1) if action[0] == 'LIST': return getList() if action[0] == 'GET': if len(action) != 2: abort(400) obj = action[1].split('.', 1) if len(obj) != 2: abort(400) key = obj[1] return getObject(key) if action[0] == 'STORE': if len(action) != 2: abort(400) return store(action[1]) if action[0] == 'DELETE': if len(action) != 2: abort(400) return delete(action[1]) abort(400)
def get_username_from_confirmation_token(app, confirmation_token): signer = Signer(app.config['SECRET_KEY'], salt='confirmation') try: username = signer.unsign(confirmation_token) except BadSignature: return None return username
def validate_fingerprints(fp_secret_key, fp_salt, client_ip_fingerprint, browser_fingerprint, client_ip, user_agent, accept_language): is_valid = True signer = Signer(fp_secret_key, fp_salt) logging.debug('client_ip_fingerprint: %s', client_ip_fingerprint) calculated_client_ip_fingerprint = signer.get_signature(client_ip) logging.debug('calculated_client_ip_fingerprint: %s', calculated_client_ip_fingerprint) if calculated_client_ip_fingerprint != client_ip_fingerprint: logging.warn('Client IP does not match fingerprint in signature') is_valid = False # TODO: # Uncomment return line below until atmobeta sends the right fingerprint signature. # Just ignore fingerprint for now. return is_valid browser_fingerprint_input = ''.join([user_agent, accept_language]) logging.debug('browser_fingerprint_input: %s', browser_fingerprint_input) logging.debug('browser_fingerprint: %s', browser_fingerprint) calculated_browser_fingerprint = signer.get_signature( browser_fingerprint_input) logging.debug('calculated_browser_fingerprint: %s', calculated_browser_fingerprint) if calculated_browser_fingerprint != browser_fingerprint: logging.warn( 'Browser fingerprint does not match calculated fingerprint') is_valid = False return is_valid
def gen_signed_code(self, identifier=None): """Generates a signed code in the format discount_code_base.randint.signature""" if not identifier: identifier = buid() signer = Signer(self.secret) key = "{base}.{identifier}".format(base=self.discount_code_base, identifier=identifier) return signer.sign(key)
def get_user(cls, token): """Use this function to validate tokens sent by users.""" # Decode token, try to fetch and verify key, and if so return user # DEVELOPMENT ACCESS if current_app.config.get("DEBUG") == True: if token == current_app.config.get("DEV_CRON_API_KEY"): return user_model.User.query.filter_by( email=current_app.config.get("DEV_CRON_EMAIL")).first() s = Signer(current_app.config["SECRET_KEY"]) try: data = s.loads(token.strip()) # Remove whitespace except: return None if not data.get("id"): return None if not data.get("key"): return None apikey = ApiKey.query.get(data.get("id")) if apikey is not None: if apikey.verify_key(data.get("key")): return user_model.User.query.get(apikey.user_id) return None
def auth_payload(user, device) -> dict: ret = { "name": user.name or "", "email": user.email, "mfa_enabled": user.enable_otp } # do not give api_key, user can only obtain api_key after OTP verification if user.enable_otp: s = Signer(FLASK_SECRET) ret["mfa_key"] = s.sign(str(user.id)) ret["api_key"] = None else: api_key = ApiKey.get_by(user_id=user.id, name=device) if not api_key: LOG.d("create new api key for %s and %s", user, device) api_key = ApiKey.create(user.id, device) db.session.commit() ret["mfa_key"] = None ret["api_key"] = api_key.code # so user is automatically logged in on the web login_user(user) return ret
def auth_mfa(): """ Validate the OTP Token Input: mfa_token: OTP token that user enters mfa_key: MFA key obtained in previous auth request, e.g. /api/auth/login device: the device name, used to create an ApiKey associated with this device Output: 200 and user info containing: { name: "John Wick", api_key: "a long string", email: "user email" } """ data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 mfa_token = data.get("mfa_token") mfa_key = data.get("mfa_key") device = data.get("device") s = Signer(FLASK_SECRET) try: user_id = int(s.unsign(mfa_key)) except Exception: return jsonify(error="Invalid mfa_key"), 400 user = User.get(user_id) if not user: return jsonify(error="Invalid mfa_key"), 400 elif not user.enable_otp: return ( jsonify( error= "This endpoint should only be used by user who enables MFA"), 400, ) totp = pyotp.TOTP(user.otp_secret) if not totp.verify(mfa_token): return jsonify(error="Wrong TOTP Token"), 400 ret = {"name": user.name or "", "email": user.email} api_key = ApiKey.get_by(user_id=user.id, name=device) if not api_key: LOG.d("create new api key for %s and %s", user, device) api_key = ApiKey.create(user.id, device) db.session.commit() ret["api_key"] = api_key.code # so user is logged in automatically on the web login_user(user) return jsonify(**ret), 200
def mailbox_confirm_change_route(): s = Signer(MAILBOX_SECRET) mailbox_id = request.args.get("mailbox_id") try: r_id = int(s.unsign(mailbox_id)) except Exception: flash("Invalid link", "error") return redirect(url_for("dashboard.index")) else: mailbox = Mailbox.get(r_id) # new_email can be None if user cancels change in the meantime if mailbox and mailbox.new_email: mailbox.email = mailbox.new_email mailbox.new_email = None # mark mailbox as verified if the change request is sent from an unverified mailbox mailbox.verified = True db.session.commit() LOG.d("Mailbox change %s is verified", mailbox) flash(f"The {mailbox.email} is updated", "success") return redirect( url_for("dashboard.mailbox_detail_route", mailbox_id=mailbox.id) ) else: flash("Invalid link", "error") return redirect(url_for("dashboard.index"))
def save_session(self, app, session, response): # we only save modified sessions if session.modified: # create a new session id if requested (by setting sid_s to None) # this makes it possible to avoid session fixation if not getattr(session, 'sid_s', None): session.sid_s = SessionID( current_app.config['SESSION_RANDOM_SOURCE'].getrandbits( app.config['SESSION_KEY_BITS'])).serialize() # save the session, now its no longer new (or modified) data = self.serialization_method.dumps(dict(session)) store = current_app.kvsession_store if getattr(store, 'ttl_support', False): # TTL is supported ttl = current_app.permanent_session_lifetime.total_seconds() store.put(session.sid_s, data, ttl) else: store.put(session.sid_s, data) session.new = False session.modified = False # save sid_s in cookie cookie_data = Signer(app.secret_key).sign( session.sid_s.encode('ascii')) response.set_cookie(key=app.config['SESSION_COOKIE_NAME'], value=cookie_data, expires=self.get_expiration_time(app, session), path=self.get_cookie_path(app), domain=self.get_cookie_domain(app), secure=app.config['SESSION_COOKIE_SECURE'], httponly=app.config['SESSION_COOKIE_HTTPONLY'])
def get(self, request): api_response = requests.post('https://api.zeit.co/oauth/access_token', { 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'code': request.raw_args['code'], }) # {"access_token":"...","token_type":"Bearer","refresh_token":"..."} access_token = api_response.json()['access_token'] # Fetch their user profile user_profile = requests.get( 'https://api.zeit.co/www/user', headers={ 'Authorization': 'Bearer {}'.format(access_token), } ).json()['user'] d = { 'access_token': access_token, 'profile': user_profile, } keen_event(request, 'login_complete', user=d) r = response.redirect('/') r.cookies['user'] = Signer(COOKIE_SECRET).sign( json.dumps(d).encode('utf8') ).decode('utf8') return r
def verify_mailbox_change(user, mailbox, new_email): s = Signer(MAILBOX_SECRET) mailbox_id_signed = s.sign(str(mailbox.id)).decode() verification_url = ( URL + "/dashboard/mailbox/confirm_change" + f"?mailbox_id={mailbox_id_signed}" ) send_email( new_email, f"Confirm mailbox change on SimpleLogin", render( "transactional/verify-mailbox-change.txt", user=user, link=verification_url, mailbox_email=mailbox.email, mailbox_new_email=new_email, ), render( "transactional/verify-mailbox-change.html", user=user, link=verification_url, mailbox_email=mailbox.email, mailbox_new_email=new_email, ), )
def confirm_user(data=None): if not get_config('verify_emails'): return redirect(url_for('challenges.challenges_view')) if data and request.method == "GET": # User is confirming email account try: s = Signer(app.config['SECRET_KEY']) email = s.unsign(urllib.unquote_plus(data.decode('base64'))) except BadSignature: return render_template( 'confirm.html', errors=['Your confirmation link seems wrong']) except: return render_template( 'confirm.html', errors=['Your link appears broken, please try again.']) team = Teams.query.filter_by(email=email).first_or_404() team.verified = True db.session.commit() db.session.close() logger = logging.getLogger('regs') logger.warn("[{0}] {1} confirmed {2}".format( time.strftime("%m/%d/%Y %X"), team.name.encode('utf-8'), team.email.encode('utf-8'))) if authed(): return redirect(url_for('challenges.challenges_view')) return redirect(url_for('auth.login')) if not data and request.method == "GET": # User has been directed to the confirm page because his account is not verified if not authed(): return redirect(url_for('auth.login')) team = Teams.query.filter_by(id=session['id']).first_or_404() if team.verified: return redirect(url_for('views.profile')) else: verify_email(team.email) return render_template('confirm.html', team=team)
def _get_signer(app): if not app.secret_key: return None return Signer(app.secret_key, salt='flask-sessions', key_derivation='hmac', digest_method=hashlib.sha256)
def notify_signup_accepted(event_name, signup): """Send an email to a user, that his signup was accepted""" id_field = current_app.config['ID_FIELD'] if signup.get('user'): lookup = {id_field: signup['user']} user = current_app.data.find_one('users', None, **lookup) name = user['firstname'] email = user['email'] else: name = 'Guest of AMIV' email = signup['email'] token = Signer(get_token_secret()).sign( str(signup[id_field]).encode('utf-8')) if current_app.config.get('SERVER_NAME') is None: current_app.logger.warning("SERVER_NAME is not set. E-Mail links " "will not work!") deletion_link = url_for('emails.on_delete_signup', token=token, _external=True) mail( current_app.config['API_MAIL'], email, '[AMIV] Eventsignup accepted', 'Hello %s!\n' '\n' 'We are happy to inform you that your signup for %s was accepted and ' 'you can come to the event! If you do not have time to attend the ' 'event please click this link to free your spot for someone else:\n' '\n%s\n\n' 'Best Regards,\n' 'The AMIV event bot' % (name, event_name, deletion_link))
def make_admin(self, req): data = JSONParser().parse(req) signer = Signer(settings.HASH_SECRET_KEY) poll_id = data['poll_id'] uid = data['user_id'] secret_token = data['secret_token'] try: unsigned_data = signer.unsign(secret_token).decode('ascii') if unsigned_data == poll_id: poll_user_object = PollUser.objects.get(pk=uid) poll_user_object.is_admin = True poll_user_object.status = 'AP' poll_user_object.save() return Response( {'msg': 'User is now superadmin for given poll'}, status=status.HTTP_201_CREATED) else: return Response({'msg': 'Invalid poll user combo'}, status=status.HTTP_400_BAD_REQUEST) except BadSignature: return Response({'msg': 'Corrupted secret token'}, status=status.HTTP_400_BAD_REQUEST) except PollUser.DoesNotExist: return Response({'msg': 'User with given ID does not exist'}, status=status.HTTP_400_BAD_REQUEST)
def reset_password(): form = ResetPasswordForm(request.form) if request.method == "POST" and form.validate(): token = form.token.data s = Signer(app.config['SECRET_KEY']) try: email = s.unsign(token) except BadSignature: return render_template("reset_invalid_token.html") user = User.query.filter_by(email=email).first() if user: user.set_password(form.password.data) print user.password login_user(user) return redirect("/") else: return render_template("reset_invalid_token.html") token = request.args.get('token', None) if not token: return render_template("reset_invalid_token.html") return render_template("reset_password.html", form=form, token=token)
def generate_key(user_id, name): """Generate a new key and return the plaintext token""" apikey = ApiKey() apikey.user_id = user_id apikey.name = name # Generate key # Want 40 char string which is urandom 20. # urandom is cryptographically secure. key = binascii.hexlify(os.urandom(20)) apikey.key = key db.session.add(apikey) db.session.commit() # Send an email about this action u = user_model.User.query.get(user_id) u.send_email( "[Alert] New API Key Issued", render_template( "email/new-api-key.html", name=name, ), force_send=True) # Generate token, which include the indexed id and key s = Signer(current_app.config["SECRET_KEY"]) return s.dumps({"id": apikey.id, "key": key})
async def save_session(self, request, response): # after each request save the session, # pass the response to set client cookies # If the session is empty, we usually do not need to save them if request['session'].is_empty() and not self.save_empty: return # Handle session refresh (to avoid, for example, "Session fixation" attack) if request['session'].refresh: await self.storage_backend.remove(request['session'].sid) request['session'].new_sid() # Save the session to the storage backend await self.storage_backend.save( request['session'].sid, request['session'], ) # Set the response cookies session_cookie = Signer(self.secret_key).sign( request['session'].sid.encode('ascii')).decode('ascii') response.cookies[self.cookie_name] = session_cookie if self.ttl: response.cookies[self.cookie_name]['max-age'] = int( self.ttl.total_seconds()) response.cookies[ self.cookie_name]['expires'] = datetime.utcnow() + self.ttl if self.domain: response.cookies[self.cookie_name]['domain'] = self.domain if self.http_only: response.cookies[self.cookie_name]['httponly'] = True
def virtual_machines_view(): # Check if authed if not utils.authed() or not 'id' in session: return redirect(url_for('auth.login', next='vm')) # Look for all vms that the team has access too (has solved the chal) vmso = VMs.query.join(Solves, Solves.teamid == int( session['id'])).filter(Solves.chalid == VMs.chalid).all() vms = [] # Set up the json data for v in vmso: signer = Signer(utils.get_config('VM_KEY'), salt=v.name, digest_method=sha256) vms.append({ 'name': v.name, 'desc': v.desc, 'key': signer.sign(json.dumps({ 'team': session['id'], 'vm': v.name })).encode('base64').replace('\n', '') }) # Run the template return render_template(PLUGIN_NAME + '/vms.html', vms=vms)
def createreportdict(lat, lng, accuracy, form): dct = {} dct["latitude"] = lat dct["longitude"] = lng dct["latitude_rand"] = lat + 0.01 * random.random() dct["longitude_rand"] = lng + 0.01 * random.random() dct["accuracy"] = accuracy dct["test"] = form.test.data dct["datetest"] = None if form.datetest.data is None else form.datetest.data.strftime("%d.%m.%Y") dct["notherstest"] = form.notherstest.data dct["symptoms"] = ', '.join(form.symptoms.data) dct["dayssymptoms"] = form.dayssymptoms.data dct["notherssymptoms"] = form.notherssymptoms.data dct["age"] = form.age.data dct["sex"] = form.sex.data dct["email_addr"] = form.email_addr.data s = Signer(form.password.data) dct["signature"] = str(s.sign(form.email_addr.data)) dct["timestamp"] = firestore.SERVER_TIMESTAMP dct["email_confirmed"] = False dct["overwritten"] = False dct["source"] = "report" dct["token"] = str(generate_confirmation_token(dct["signature"])) return dct
def login(): print "\033[32mWelcome to the \033[33mHack The Vote 2016 \033[32mSession system\033[0m" print "You are requesting a session for 'ballot return'" print print "Please enter your team password to continue (found in the challenge description):" print ">>", pw = raw_input() try: teamid = Signer(SECRET_KEY).unsign(pw) except Exception as e: print "\033[31mInvalid password!" exit() username = teamid.replace('/', '') # Create user if not exist try: pwd.getpwnam(username) print "\033[32mUser already exists", except KeyError: if not makeuser(username, pw): print "Error creating user. ping @clarkb7" exit() print "\033[32mYou may now", print "\033[33m`ssh ballot{}@ballotreturn.pwn.democrat` \033[32mwith your secret to cast your vote\033[0m".format( username)
def signup(): data = request.get_json() app_root = os.getcwd() s = Signer('superpowerfullkey') token = s.sign(data['email'].encode()).decode() token = token[::-1].split('.')[0][::-1] if 'type' not in data: data['type'] = False image_path = None else: import base64 byte_image = base64.b64decode(data['image']) if not os.path.isdir(os.path.join(app_root, "images/")): os.mkdir(os.path.join(app_root, "images/")) image_path = os.path.join( os.path.join(app_root, "images/"), data['first_name'] + ' ' + data['last_name'] + '.jpg') with open(image_path, 'wb') as f: f.write(byte_image) newuser = User(data['first_name'], data['last_name'], data['email'], data['password'], token, data['type'], filepath_=image_path if image_path is not None else None) db.session.add(newuser) db.session.commit() return jsonify(status='success', token=token)
def captcha(publicID): publicID = publicID.lower() session_info = session_db.find_one({"publicID": publicID}, {"_id": 0}) hancock = Signer(str(secret_key), salt=str(session_info["privateID"])) if (publicID + "-guest") in request.cookies and hancock.validate( request.cookies.get(publicID + "-guest")): return redirect("https://www.crowdsourcejukebox.com/vote/" + publicID + "/") if request.method == "POST": captcha_response = request.form["g-recaptcha-response"] if is_human(captcha_response): resp = make_response( redirect("https://www.crowdsourcejukebox.com/vote/" + publicID + "/")) guestID = bytes(str(uuid.uuid4()), "utf-8") session_db.update_one({"publicID": publicID}, {"$inc": { "guests": 1 }}) resp.set_cookie( publicID + "-guest", value=hancock.sign(guestID), expires=datetime.datetime.now() + datetime.timedelta(hours=1), ) return resp else: return redirect("http://www.crowdsourcejukebox.com/") else: return render_template("captcha.html", sitekey=os.environ["RC_SITE_KEY"])
def test_auth_mfa_success(flask_client): user = User.create( email="[email protected]", password="******", name="Test User", activated=True, enable_otp=True, otp_secret="base32secret3232", ) db.session.commit() totp = pyotp.TOTP(user.otp_secret) s = Signer(FLASK_SECRET) mfa_key = s.sign(str(user.id)) r = flask_client.post( url_for("api.auth_mfa"), json={ "mfa_token": totp.now(), "mfa_key": mfa_key, "device": "Test Device" }, ) assert r.status_code == 200 assert r.json["api_key"] assert r.json["name"] == "Test User"
def validate_machine_token(self, token): s = Signer(self.secret) try: s.unsign(token) return True except BadSignature: return False
def sign(): # if request.method == 'GET': # # return render_template('user_signup.html') # elif request.method == 'POST': # name = request.form.get('name') # email=request.form.get('email') # password=request.form.get('password') # phone = request.form.get('phone') # address = request.form.get('address') # newUser = p.PeopleProfile(name,email,password, phone, address) # db.session.add(newUser) # db.session.commit() # flash('Record were added successfully') # return render_template('user_signup.html' ) if request.method == 'POST': email = request.form.get("email") print email userS = p.PeopleProfile.query.filter_by(email=email).first() if userS: if userS.email == email: session['email'] = userS.email flash('email already registered') return render_template('user_signup.html') else: name = request.form.get('name') email = request.form.get('email') password = request.form.get('password') # hashpw = hash_password(password) phone = request.form.get('phone') address = request.form.get('address') bloodCategoryId = request.form.get('bloodCategory') # newUser = p.PeopleProfile(email = email) newUser = p.PeopleProfile(name, email, password, phone, address, bloodCategoryId) newUser.hash_password(password) db.session.add(newUser) db.session.commit() signer = Signer(app.secret_key) token = signer.sign(email) url = url_for('confirmation', token=token, _external=True) msg = Message( "E-mail confirmation for Sahayog - A Blood Donation Portal", sender="*****@*****.**", recipients=[email]) msg.body = url # flash(msg.body) mail.send(msg) flash('Record were added successfully') return render_template('user_signup.html') elif request.method == 'GET': bloodCategoryL = b.BloodCategory.query.all() return render_template('user_signup.html', bloodCategoryList=bloodCategoryL)