2022-06-02 11:24:04 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import base64
|
2023-04-06 11:07:13 +02:00
|
|
|
import dataclasses
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
import enum
|
2022-06-02 11:24:04 +02:00
|
|
|
import hashlib
|
|
|
|
import hmac
|
2022-01-24 16:10:36 +01:00
|
|
|
import os
|
2019-07-22 17:28:31 +02:00
|
|
|
import random
|
2022-08-10 18:48:32 +02:00
|
|
|
import secrets
|
2019-12-26 12:21:28 +01:00
|
|
|
import uuid
|
2022-06-20 14:34:20 +02:00
|
|
|
from typing import List, Tuple, Optional, Union
|
2019-07-01 17:18:12 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
import arrow
|
2021-08-21 16:04:32 +02:00
|
|
|
import sqlalchemy as sa
|
2020-08-04 11:36:53 +02:00
|
|
|
from arrow import Arrow
|
2022-01-06 15:29:37 +01:00
|
|
|
from email_validator import validate_email
|
2021-09-10 17:06:38 +02:00
|
|
|
from flanker.addresslib import address
|
2019-07-22 17:28:31 +02:00
|
|
|
from flask import url_for
|
2019-07-01 17:18:12 +02:00
|
|
|
from flask_login import UserMixin
|
2022-01-24 16:10:36 +01:00
|
|
|
from jinja2 import FileSystemLoader, Environment
|
2023-04-04 15:21:51 +02:00
|
|
|
from sqlalchemy import orm, or_
|
2021-08-17 19:02:35 +02:00
|
|
|
from sqlalchemy import text, desc, CheckConstraint, Index, Column
|
2021-08-21 16:04:32 +02:00
|
|
|
from sqlalchemy.dialects.postgresql import TSVECTOR
|
2021-10-12 14:36:47 +02:00
|
|
|
from sqlalchemy.ext.declarative import declarative_base
|
2021-10-25 14:47:07 +02:00
|
|
|
from sqlalchemy.orm import deferred
|
2022-06-02 11:24:04 +02:00
|
|
|
from sqlalchemy.sql import and_
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
from sqlalchemy_utils import ArrowType
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2024-01-30 18:29:59 +01:00
|
|
|
from app import config, rate_limiter
|
2022-09-05 08:40:24 +02:00
|
|
|
from app import s3
|
2021-10-12 14:36:47 +02:00
|
|
|
from app.db import Session
|
2023-08-09 09:56:53 +02:00
|
|
|
from app.dns_utils import get_mx_domains
|
|
|
|
|
2022-01-07 10:04:12 +01:00
|
|
|
from app.errors import (
|
|
|
|
AliasInTrashError,
|
|
|
|
DirectoryInTrashError,
|
|
|
|
SubdomainInTrashError,
|
|
|
|
CannotCreateContactForReverseAlias,
|
|
|
|
)
|
2022-06-30 11:40:01 +02:00
|
|
|
from app.handler.unsubscribe_encoder import UnsubscribeAction, UnsubscribeEncoder
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
from app.log import LOG
|
2019-07-03 12:13:28 +02:00
|
|
|
from app.oauth_models import Scope
|
2021-05-26 18:17:47 +02:00
|
|
|
from app.pw_models import PasswordOracle
|
2021-01-11 12:29:40 +01:00
|
|
|
from app.utils import (
|
|
|
|
convert_to_id,
|
|
|
|
random_string,
|
|
|
|
random_words,
|
|
|
|
sanitize_email,
|
|
|
|
)
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
Base = declarative_base()
|
|
|
|
|
2022-05-11 19:03:27 +02:00
|
|
|
PADDLE_SUBSCRIPTION_GRACE_DAYS = 14
|
2022-06-09 10:19:49 +02:00
|
|
|
_PARTNER_SUBSCRIPTION_GRACE_DAYS = 14
|
2022-05-11 19:03:27 +02:00
|
|
|
|
2021-08-04 09:29:56 +02:00
|
|
|
|
|
|
|
class TSVector(sa.types.TypeDecorator):
|
|
|
|
impl = TSVECTOR
|
|
|
|
|
2019-07-01 17:18:12 +02:00
|
|
|
|
|
|
|
class ModelMixin(object):
|
2021-10-12 14:36:47 +02:00
|
|
|
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
|
|
|
created_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
|
|
|
updated_at = sa.Column(ArrowType, default=None, onupdate=arrow.utcnow)
|
2019-07-01 17:18:12 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
_repr_hide = ["created_at", "updated_at"]
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def query(cls):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Session.query(cls)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2022-01-06 18:50:54 +01:00
|
|
|
@classmethod
|
|
|
|
def yield_per_query(cls, page=1000):
|
|
|
|
"""to be used when iterating on a big table to avoid taking all the memory"""
|
|
|
|
return Session.query(cls).yield_per(page).enable_eagerloads(False)
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
@classmethod
|
|
|
|
def get(cls, id):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Session.query(cls).get(id)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_by(cls, **kw):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Session.query(cls).filter_by(**kw).first()
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def filter_by(cls, **kw):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Session.query(cls).filter_by(**kw)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def filter(cls, *args, **kw):
|
|
|
|
return Session.query(cls).filter(*args, **kw)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def order_by(cls, *args, **kw):
|
|
|
|
return Session.query(cls).order_by(*args, **kw)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def all(cls):
|
|
|
|
return Session.query(cls).all()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def count(cls):
|
|
|
|
return Session.query(cls).count()
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_or_create(cls, **kw):
|
|
|
|
r = cls.get_by(**kw)
|
|
|
|
if not r:
|
|
|
|
r = cls(**kw)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.add(r)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
return r
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
2022-01-07 10:04:12 +01:00
|
|
|
# whether to call Session.commit
|
2020-09-28 17:40:30 +02:00
|
|
|
commit = kw.pop("commit", False)
|
2021-09-20 18:16:52 +02:00
|
|
|
flush = kw.pop("flush", False)
|
2020-09-28 17:40:30 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
r = cls(**kw)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.add(r)
|
2020-09-28 17:40:30 +02:00
|
|
|
|
|
|
|
if commit:
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2021-09-20 18:16:52 +02:00
|
|
|
|
|
|
|
if flush:
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.flush()
|
2021-09-20 18:16:52 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
return r
|
|
|
|
|
|
|
|
def save(self):
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.add(self)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-05-22 16:50:03 +02:00
|
|
|
@classmethod
|
2022-01-08 00:28:26 +01:00
|
|
|
def delete(cls, obj_id, commit=False):
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.query(cls).filter(cls.id == obj_id).delete()
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2022-01-08 00:28:26 +01:00
|
|
|
if commit:
|
|
|
|
Session.commit()
|
|
|
|
|
2020-11-03 11:13:43 +01:00
|
|
|
@classmethod
|
|
|
|
def first(cls):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Session.query(cls).first()
|
2020-11-03 11:13:43 +01:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
def __repr__(self):
|
|
|
|
values = ", ".join(
|
|
|
|
"%s=%r" % (n, getattr(self, n))
|
|
|
|
for n in self.__table__.c.keys()
|
|
|
|
if n not in self._repr_hide
|
|
|
|
)
|
|
|
|
return "%s(%s)" % (self.__class__.__name__, values)
|
2019-07-01 17:18:12 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class File(Base, ModelMixin):
|
|
|
|
__tablename__ = "file"
|
|
|
|
path = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=True)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-22 18:14:32 +02:00
|
|
|
def get_url(self, expires_in=3600):
|
|
|
|
return s3.get_url(self.path, expires_in)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-09-10 20:05:25 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<File {self.path}>"
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-05-15 16:14:12 +02:00
|
|
|
class EnumE(enum.Enum):
|
|
|
|
@classmethod
|
|
|
|
def has_value(cls, value: int) -> bool:
|
|
|
|
return value in set(item.value for item in cls)
|
|
|
|
|
2020-11-15 19:34:00 +01:00
|
|
|
@classmethod
|
2020-11-15 19:43:01 +01:00
|
|
|
def get_name(cls, value: int) -> Optional[str]:
|
2020-11-15 19:34:00 +01:00
|
|
|
for item in cls:
|
|
|
|
if item.value == value:
|
|
|
|
return item.name
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
2020-11-15 19:43:01 +01:00
|
|
|
@classmethod
|
|
|
|
def has_name(cls, name: str) -> bool:
|
|
|
|
for item in cls:
|
|
|
|
if item.name == name:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_value(cls, name: str) -> Optional[int]:
|
|
|
|
for item in cls:
|
|
|
|
if item.name == name:
|
|
|
|
return item.value
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
2020-05-15 16:14:12 +02:00
|
|
|
|
|
|
|
class PlanEnum(EnumE):
|
2019-11-14 14:52:33 +01:00
|
|
|
monthly = 2
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
yearly = 3
|
2019-07-01 17:18:12 +02:00
|
|
|
|
|
|
|
|
2020-05-15 16:14:12 +02:00
|
|
|
# Specify the format for sender address
|
|
|
|
class SenderFormatEnum(EnumE):
|
|
|
|
AT = 0 # John Wick - john at wick.com
|
|
|
|
A = 2 # John Wick - john(a)wick.com
|
2021-12-28 10:49:37 +01:00
|
|
|
NAME_ONLY = 5 # John Wick
|
|
|
|
AT_ONLY = 6 # john at wick.com
|
|
|
|
NO_NAME = 7
|
2020-05-15 16:14:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
class AliasGeneratorEnum(EnumE):
|
2019-12-26 12:21:28 +01:00
|
|
|
word = 1 # aliases are generated based on random words
|
|
|
|
uuid = 2 # aliases are generated based on uuid
|
|
|
|
|
2021-05-14 04:29:26 +02:00
|
|
|
|
2021-05-14 01:53:01 +02:00
|
|
|
class AliasSuffixEnum(EnumE):
|
|
|
|
word = 0 # Random word from dictionary file
|
2021-05-14 20:03:16 +02:00
|
|
|
random_string = 1 # Completely random string
|
2019-12-26 12:21:28 +01:00
|
|
|
|
2021-05-27 07:34:50 +02:00
|
|
|
|
2022-02-21 12:52:21 +01:00
|
|
|
class BlockBehaviourEnum(EnumE):
|
|
|
|
return_2xx = 0
|
|
|
|
return_5xx = 1
|
|
|
|
|
|
|
|
|
2022-03-11 11:37:14 +01:00
|
|
|
class AuditLogActionEnum(EnumE):
|
|
|
|
create_object = 0
|
|
|
|
update_object = 1
|
|
|
|
delete_object = 2
|
|
|
|
manual_upgrade = 3
|
|
|
|
extend_trial = 4
|
|
|
|
disable_2fa = 5
|
|
|
|
logged_as_user = 6
|
2022-03-14 15:07:51 +01:00
|
|
|
extend_subscription = 7
|
2022-04-25 14:40:42 +02:00
|
|
|
download_provider_complaint = 8
|
2022-11-28 10:39:18 +01:00
|
|
|
disable_user = 9
|
|
|
|
enable_user = 10
|
2024-02-05 13:47:39 +01:00
|
|
|
stop_trial = 11
|
2022-04-14 18:46:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Phase(EnumE):
|
|
|
|
unknown = 0
|
|
|
|
forward = 1
|
|
|
|
reply = 2
|
2022-03-11 11:37:14 +01:00
|
|
|
|
|
|
|
|
2022-03-25 18:14:31 +01:00
|
|
|
class VerpType(EnumE):
|
|
|
|
bounce_forward = 0
|
|
|
|
bounce_reply = 1
|
|
|
|
transactional = 2
|
|
|
|
|
|
|
|
|
2022-06-28 09:22:48 +02:00
|
|
|
class JobState(EnumE):
|
|
|
|
ready = 0
|
|
|
|
taken = 1
|
|
|
|
done = 2
|
|
|
|
error = 3
|
|
|
|
|
|
|
|
|
2022-07-19 17:25:21 +02:00
|
|
|
class UnsubscribeBehaviourEnum(EnumE):
|
|
|
|
DisableAlias = 0
|
|
|
|
BlockContact = 1
|
|
|
|
PreserveOriginal = 2
|
|
|
|
|
|
|
|
|
2024-07-08 16:39:18 +02:00
|
|
|
class AliasDeleteReason(EnumE):
|
|
|
|
Unspecified = 0
|
|
|
|
UserHasBeenDeleted = 1
|
|
|
|
ManualAction = 2
|
|
|
|
DirectoryDeleted = 3
|
|
|
|
MailboxDeleted = 4
|
|
|
|
CustomDomainDeleted = 5
|
|
|
|
|
|
|
|
|
2022-07-19 17:25:21 +02:00
|
|
|
class IntEnumType(sa.types.TypeDecorator):
|
|
|
|
impl = sa.Integer
|
|
|
|
|
|
|
|
def __init__(self, enumtype, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self._enum_type = enumtype
|
|
|
|
|
|
|
|
def process_bind_param(self, enum_obj, dialect):
|
|
|
|
return enum_obj.value
|
|
|
|
|
|
|
|
def process_result_value(self, enum_value, dialect):
|
|
|
|
return self._enum_type(enum_value)
|
|
|
|
|
|
|
|
|
2023-04-06 11:07:13 +02:00
|
|
|
@dataclasses.dataclass
|
|
|
|
class AliasOptions:
|
|
|
|
show_sl_domains: bool = True
|
|
|
|
show_partner_domains: Optional[Partner] = None
|
2023-09-13 18:12:47 +02:00
|
|
|
show_partner_premium: Optional[bool] = None
|
2023-04-06 11:07:13 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Hibp(Base, ModelMixin):
|
2021-05-13 22:44:16 +02:00
|
|
|
__tablename__ = "hibp"
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(), nullable=False, unique=True, index=True)
|
|
|
|
breached_aliases = orm.relationship("Alias", secondary="alias_hibp")
|
2021-05-13 22:44:16 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
description = sa.Column(sa.Text)
|
|
|
|
date = sa.Column(ArrowType, nullable=True)
|
2021-07-29 08:51:21 +02:00
|
|
|
|
2021-05-19 12:46:55 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<HIBP Breach {self.id} {self.name}>"
|
|
|
|
|
2021-05-13 22:44:16 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class HibpNotifiedAlias(Base, ModelMixin):
|
2021-07-29 09:41:46 +02:00
|
|
|
"""Contain list of aliases that have been notified to users
|
|
|
|
So that we can only notify users of new aliases.
|
|
|
|
"""
|
|
|
|
|
|
|
|
__tablename__ = "hibp_notified_alias"
|
2023-04-14 19:08:52 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey("alias.id", ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=False)
|
2021-07-29 09:41:46 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
notified_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
2021-07-29 09:41:46 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Fido(Base, ModelMixin):
|
2020-05-18 07:05:37 +02:00
|
|
|
__tablename__ = "fido"
|
2021-10-12 14:36:47 +02:00
|
|
|
credential_id = sa.Column(sa.String(), nullable=False, unique=True, index=True)
|
|
|
|
uuid = sa.Column(
|
|
|
|
sa.ForeignKey("users.fido_uuid", ondelete="cascade"),
|
2020-05-18 09:06:24 +02:00
|
|
|
unique=False,
|
|
|
|
nullable=False,
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
public_key = sa.Column(sa.String(), nullable=False, unique=True)
|
2021-11-06 12:40:16 +01:00
|
|
|
sign_count = sa.Column(sa.BigInteger(), nullable=False)
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(128), nullable=False, unique=False)
|
2021-11-22 15:57:38 +01:00
|
|
|
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=True)
|
2019-12-26 12:21:28 +01:00
|
|
|
|
2020-05-18 09:06:24 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class User(Base, ModelMixin, UserMixin, PasswordOracle):
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
__tablename__ = "users"
|
2022-04-21 18:40:24 +02:00
|
|
|
|
2024-09-27 16:04:32 +02:00
|
|
|
FLAG_DISABLE_CREATE_CONTACTS = 1 << 0
|
2022-06-16 10:25:50 +02:00
|
|
|
FLAG_CREATED_FROM_PARTNER = 1 << 1
|
2022-07-20 11:09:22 +02:00
|
|
|
FLAG_FREE_OLD_ALIAS_LIMIT = 1 << 2
|
2024-06-28 15:34:16 +02:00
|
|
|
FLAG_CREATED_ALIAS_FROM_PARTNER = 1 << 3
|
2022-04-21 18:40:24 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
email = sa.Column(sa.String(256), unique=True, nullable=False)
|
2020-02-27 16:18:26 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(128), nullable=True)
|
|
|
|
is_admin = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
|
|
alias_generator = sa.Column(
|
|
|
|
sa.Integer,
|
2019-12-28 01:03:59 +01:00
|
|
|
nullable=False,
|
|
|
|
default=AliasGeneratorEnum.word.value,
|
|
|
|
server_default=str(AliasGeneratorEnum.word.value),
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
notification = sa.Column(
|
|
|
|
sa.Boolean, default=True, nullable=False, server_default="1"
|
2019-12-30 00:37:07 +01:00
|
|
|
)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2023-07-29 10:03:31 +02:00
|
|
|
activated = sa.Column(sa.Boolean, default=False, nullable=False, index=True)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-10-04 12:48:28 +02:00
|
|
|
# an account can be disabled if having harmful behavior
|
2021-10-12 14:36:47 +02:00
|
|
|
disabled = sa.Column(sa.Boolean, default=False, nullable=False, server_default="0")
|
2020-10-04 12:48:28 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
profile_picture_id = sa.Column(sa.ForeignKey(File.id), nullable=True)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
otp_secret = sa.Column(sa.String(16), nullable=True)
|
|
|
|
enable_otp = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2019-12-27 15:20:10 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
last_otp = sa.Column(sa.String(12), nullable=True, default=False)
|
2019-12-27 15:20:10 +01:00
|
|
|
|
2020-05-05 10:32:49 +02:00
|
|
|
# Fields for WebAuthn
|
2021-10-12 14:36:47 +02:00
|
|
|
fido_uuid = sa.Column(sa.String(), nullable=True, unique=True)
|
2020-05-05 10:32:49 +02:00
|
|
|
|
2020-07-04 23:19:21 +02:00
|
|
|
# the default domain that's used when user creates a new random alias
|
2020-12-31 14:14:56 +01:00
|
|
|
# default_alias_custom_domain_id XOR default_alias_public_domain_id
|
2021-10-12 14:36:47 +02:00
|
|
|
default_alias_custom_domain_id = sa.Column(
|
|
|
|
sa.ForeignKey("custom_domain.id", ondelete="SET NULL"),
|
2020-07-04 23:19:21 +02:00
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
default_alias_public_domain_id = sa.Column(
|
|
|
|
sa.ForeignKey("public_domain.id", ondelete="SET NULL"),
|
2020-07-04 23:19:21 +02:00
|
|
|
nullable=True,
|
|
|
|
default=None,
|
2020-06-25 13:02:43 +02:00
|
|
|
)
|
|
|
|
|
2020-01-01 20:02:30 +01:00
|
|
|
# some users could have lifetime premium
|
2021-10-12 14:36:47 +02:00
|
|
|
lifetime = sa.Column(sa.Boolean, default=False, nullable=False, server_default="0")
|
|
|
|
paid_lifetime = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2020-05-27 00:18:45 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
lifetime_coupon_id = sa.Column(
|
|
|
|
sa.ForeignKey("lifetime_coupon.id", ondelete="SET NULL"),
|
2021-10-04 17:14:34 +02:00
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
)
|
2020-01-01 20:02:30 +01:00
|
|
|
|
2020-01-30 04:10:28 +01:00
|
|
|
# user can use all premium features until this date
|
2021-10-12 14:36:47 +02:00
|
|
|
trial_end = sa.Column(
|
2020-01-30 04:52:56 +01:00
|
|
|
ArrowType, default=lambda: arrow.now().shift(days=7, hours=1), nullable=True
|
2020-01-30 04:10:28 +01:00
|
|
|
)
|
|
|
|
|
2020-02-23 09:40:41 +01:00
|
|
|
# the mailbox used when create random alias
|
2020-03-05 17:00:43 +01:00
|
|
|
# this field is nullable but in practice, it's always set
|
|
|
|
# it cannot be set to non-nullable though
|
|
|
|
# as this will create foreign key cycle between User and Mailbox
|
2021-10-12 14:36:47 +02:00
|
|
|
default_mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey("mailbox.id"), nullable=True, default=None
|
2020-02-23 09:40:41 +01:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
profile_picture = orm.relationship(File, foreign_keys=[profile_picture_id])
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-05-15 16:14:12 +02:00
|
|
|
# Specify the format for sender address
|
2022-01-12 10:19:25 +01:00
|
|
|
# for the full list, see SenderFormatEnum
|
2021-10-12 14:36:47 +02:00
|
|
|
sender_format = sa.Column(
|
|
|
|
sa.Integer, default="0", nullable=False, server_default="0"
|
2020-03-28 22:35:29 +01:00
|
|
|
)
|
2021-01-26 20:13:51 +01:00
|
|
|
# to know whether user has explicitly chosen a sender format as opposed to those who use the default ones.
|
|
|
|
# users who haven't chosen a sender format and are using 1 or 3 format, their sender format will be set to 0
|
2021-10-12 14:36:47 +02:00
|
|
|
sender_format_updated_at = sa.Column(ArrowType, default=None)
|
2020-03-28 22:35:29 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
replace_reverse_alias = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2020-05-17 14:53:43 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
referral_id = sa.Column(
|
2023-07-29 10:03:31 +02:00
|
|
|
sa.ForeignKey("referral.id", ondelete="SET NULL"),
|
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
index=True,
|
2020-05-02 18:08:05 +02:00
|
|
|
)
|
2020-04-09 22:19:45 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
referral = orm.relationship("Referral", foreign_keys=[referral_id])
|
2020-04-09 22:19:45 +02:00
|
|
|
|
2020-04-13 13:22:52 +02:00
|
|
|
# whether intro has been shown to user
|
2021-10-12 14:36:47 +02:00
|
|
|
intro_shown = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2020-04-13 13:22:52 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
default_mailbox = orm.relationship("Mailbox", foreign_keys=[default_mailbox_id])
|
2020-05-03 15:54:19 +02:00
|
|
|
|
2020-07-23 11:09:28 +02:00
|
|
|
# user can set a more strict max_spam score to block spams more aggressively
|
2021-10-12 14:36:47 +02:00
|
|
|
max_spam_score = sa.Column(sa.Integer, nullable=True)
|
2020-07-23 11:09:28 +02:00
|
|
|
|
2020-09-12 14:30:49 +02:00
|
|
|
# newsletter is sent to this address
|
2021-10-12 14:36:47 +02:00
|
|
|
newsletter_alias_id = sa.Column(
|
2023-04-14 19:08:52 +02:00
|
|
|
sa.ForeignKey("alias.id", ondelete="SET NULL"),
|
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
index=True,
|
2020-09-12 14:30:49 +02:00
|
|
|
)
|
|
|
|
|
2020-12-06 19:25:55 +01:00
|
|
|
# whether to include the sender address in reverse-alias
|
2021-10-12 14:36:47 +02:00
|
|
|
include_sender_in_reverse_alias = sa.Column(
|
2022-08-23 11:24:49 +02:00
|
|
|
sa.Boolean, default=True, nullable=False, server_default="0"
|
2020-12-06 19:25:55 +01:00
|
|
|
)
|
|
|
|
|
2021-05-14 01:13:19 +02:00
|
|
|
# whether to use random string or random word as suffix
|
2021-05-14 01:53:01 +02:00
|
|
|
# Random word from dictionary file -> 0
|
|
|
|
# Completely random string -> 1
|
2021-10-12 14:36:47 +02:00
|
|
|
random_alias_suffix = sa.Column(
|
|
|
|
sa.Integer,
|
2021-05-14 04:29:26 +02:00
|
|
|
nullable=False,
|
2023-06-27 11:07:02 +02:00
|
|
|
default=AliasSuffixEnum.word.value,
|
2021-05-14 20:03:16 +02:00
|
|
|
server_default=str(AliasSuffixEnum.random_string.value),
|
2021-05-14 01:13:19 +02:00
|
|
|
)
|
|
|
|
|
2021-07-22 10:17:23 +02:00
|
|
|
# always expand the alias info, i.e. without needing to press "More"
|
2021-10-12 14:36:47 +02:00
|
|
|
expand_alias_info = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2021-07-22 10:17:23 +02:00
|
|
|
)
|
|
|
|
|
2021-09-10 18:14:51 +02:00
|
|
|
# ignore emails send from a mailbox to its alias. This can happen when replying all to a forwarded email
|
|
|
|
# can automatically re-includes the alias
|
2021-10-12 14:36:47 +02:00
|
|
|
ignore_loop_email = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2021-09-10 18:14:51 +02:00
|
|
|
)
|
|
|
|
|
2021-10-11 11:30:10 +02:00
|
|
|
# used for flask-login as an "alternative token"
|
|
|
|
# cf https://flask-login.readthedocs.io/en/latest/#alternative-tokens
|
2021-10-12 14:36:47 +02:00
|
|
|
alternative_id = sa.Column(sa.String(128), unique=True, nullable=True)
|
2021-10-11 11:30:10 +02:00
|
|
|
|
2021-10-23 17:40:57 +02:00
|
|
|
# by default, when an alias is automatically created, a note like "Created with ...." is created
|
|
|
|
# If this field is True, the note won't be created.
|
|
|
|
disable_automatic_alias_note = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2021-11-02 15:41:49 +01:00
|
|
|
# By default, the one-click unsubscribe disable the alias
|
|
|
|
# If set to true, it will block the sender instead
|
|
|
|
one_click_unsubscribe_block_sender = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2021-11-12 09:44:40 +01:00
|
|
|
# automatically include the website name when user creates an alias via the SimpleLogin icon in the email field
|
|
|
|
include_website_in_one_click_alias = sa.Column(
|
|
|
|
sa.Boolean,
|
|
|
|
# new user will have this option turned on automatically
|
|
|
|
default=True,
|
|
|
|
nullable=False,
|
|
|
|
# old user will have this option turned off
|
|
|
|
server_default="0",
|
|
|
|
)
|
|
|
|
|
2021-11-18 10:30:46 +01:00
|
|
|
_directory_quota = sa.Column(
|
|
|
|
"directory_quota", sa.Integer, default=50, nullable=False, server_default="50"
|
|
|
|
)
|
|
|
|
|
|
|
|
_subdomain_quota = sa.Column(
|
|
|
|
"subdomain_quota", sa.Integer, default=5, nullable=False, server_default="5"
|
|
|
|
)
|
|
|
|
|
2021-11-18 10:51:13 +01:00
|
|
|
# user can use import to import too many aliases
|
|
|
|
disable_import = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2021-12-02 16:50:26 +01:00
|
|
|
# user can use the phone feature
|
|
|
|
can_use_phone = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
|
|
|
# in minutes
|
|
|
|
phone_quota = sa.Column(sa.Integer, nullable=True)
|
|
|
|
|
2022-02-21 12:52:21 +01:00
|
|
|
# Status code to return if is blocked
|
|
|
|
block_behaviour = sa.Column(
|
|
|
|
sa.Enum(BlockBehaviourEnum),
|
|
|
|
nullable=False,
|
|
|
|
server_default=BlockBehaviourEnum.return_2xx.name,
|
|
|
|
)
|
|
|
|
|
2022-02-25 12:17:45 +01:00
|
|
|
include_header_email_header = sa.Column(
|
2023-06-22 10:40:32 +02:00
|
|
|
sa.Boolean, default=True, nullable=False, server_default="1"
|
2022-02-25 12:17:45 +01:00
|
|
|
)
|
|
|
|
|
2024-04-12 10:39:23 +02:00
|
|
|
# user opted in for data breach check
|
|
|
|
enable_data_breach_check = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2022-04-21 18:40:24 +02:00
|
|
|
# bitwise flags. Allow for future expansion
|
|
|
|
flags = sa.Column(
|
|
|
|
sa.BigInteger,
|
2024-09-27 16:04:32 +02:00
|
|
|
default=FLAG_DISABLE_CREATE_CONTACTS,
|
2022-04-21 18:40:24 +02:00
|
|
|
server_default="0",
|
|
|
|
nullable=False,
|
|
|
|
)
|
|
|
|
|
2022-07-19 17:25:21 +02:00
|
|
|
# Keep original unsub behaviour
|
|
|
|
unsub_behaviour = sa.Column(
|
|
|
|
IntEnumType(UnsubscribeBehaviourEnum),
|
2023-03-22 15:47:40 +01:00
|
|
|
default=UnsubscribeBehaviourEnum.PreserveOriginal,
|
2022-07-20 11:57:34 +02:00
|
|
|
server_default=str(UnsubscribeBehaviourEnum.DisableAlias.value),
|
2022-07-19 17:25:21 +02:00
|
|
|
nullable=False,
|
|
|
|
)
|
|
|
|
|
2023-09-10 22:11:50 +02:00
|
|
|
# Trigger hard deletion of the account at this time
|
|
|
|
delete_on = sa.Column(ArrowType, default=None)
|
|
|
|
|
2023-07-29 10:03:31 +02:00
|
|
|
__table_args__ = (
|
|
|
|
sa.Index(
|
|
|
|
"ix_users_activated_trial_end_lifetime", activated, trial_end, lifetime
|
|
|
|
),
|
2023-09-10 22:11:50 +02:00
|
|
|
sa.Index("ix_users_delete_on", delete_on),
|
2023-07-29 10:03:31 +02:00
|
|
|
)
|
|
|
|
|
2021-11-18 10:30:46 +01:00
|
|
|
@property
|
|
|
|
def directory_quota(self):
|
|
|
|
return min(
|
|
|
|
self._directory_quota,
|
2022-06-30 11:40:01 +02:00
|
|
|
config.MAX_NB_DIRECTORY - Directory.filter_by(user_id=self.id).count(),
|
2021-11-18 10:30:46 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def subdomain_quota(self):
|
|
|
|
return min(
|
|
|
|
self._subdomain_quota,
|
2022-06-30 11:40:01 +02:00
|
|
|
config.MAX_NB_SUBDOMAIN
|
2021-11-18 10:30:46 +01:00
|
|
|
- CustomDomain.filter_by(user_id=self.id, is_sl_subdomain=True).count(),
|
|
|
|
)
|
|
|
|
|
2022-06-28 11:57:21 +02:00
|
|
|
@property
|
|
|
|
def created_by_partner(self):
|
|
|
|
return User.FLAG_CREATED_FROM_PARTNER == (
|
|
|
|
self.flags & User.FLAG_CREATED_FROM_PARTNER
|
|
|
|
)
|
|
|
|
|
2021-11-05 18:10:56 +01:00
|
|
|
@staticmethod
|
|
|
|
def subdomain_is_available():
|
|
|
|
return SLDomain.filter_by(can_use_subdomain=True).count() > 0
|
|
|
|
|
2021-10-11 11:30:10 +02:00
|
|
|
# implement flask-login "alternative token"
|
|
|
|
def get_id(self):
|
|
|
|
if self.alternative_id:
|
|
|
|
return self.alternative_id
|
|
|
|
else:
|
|
|
|
return str(self.id)
|
|
|
|
|
2019-07-12 10:34:15 +02:00
|
|
|
@classmethod
|
2022-06-16 10:25:50 +02:00
|
|
|
def create(cls, email, name="", password=None, from_partner=False, **kwargs):
|
2023-08-03 10:20:25 +02:00
|
|
|
email = sanitize_email(email)
|
2023-04-20 11:06:59 +02:00
|
|
|
user: User = super(User, cls).create(email=email, name=name[:100], **kwargs)
|
2019-07-12 10:34:15 +02:00
|
|
|
|
2020-02-27 16:15:22 +01:00
|
|
|
if password:
|
|
|
|
user.set_password(password)
|
2020-02-27 16:31:38 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.flush()
|
2019-07-12 10:34:15 +02:00
|
|
|
|
2020-02-28 16:53:13 +01:00
|
|
|
mb = Mailbox.create(user_id=user.id, email=user.email, verified=True)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.flush()
|
2020-02-28 16:53:13 +01:00
|
|
|
user.default_mailbox_id = mb.id
|
2020-02-23 07:58:09 +01:00
|
|
|
|
2021-10-11 11:47:07 +02:00
|
|
|
# generate an alternative_id if needed
|
|
|
|
if "alternative_id" not in kwargs:
|
|
|
|
user.alternative_id = str(uuid.uuid4())
|
|
|
|
|
2022-06-16 10:25:50 +02:00
|
|
|
# If the user is created from partner, do not notify
|
|
|
|
# nor give a trial
|
|
|
|
if from_partner:
|
|
|
|
user.flags = User.FLAG_CREATED_FROM_PARTNER
|
|
|
|
user.notification = False
|
|
|
|
user.trial_end = None
|
2022-06-20 11:36:16 +02:00
|
|
|
Job.create(
|
2022-06-30 11:40:01 +02:00
|
|
|
name=config.JOB_SEND_PROTON_WELCOME_1,
|
2022-06-20 11:36:16 +02:00
|
|
|
payload={"user_id": user.id},
|
|
|
|
run_at=arrow.now(),
|
|
|
|
)
|
2022-06-16 10:25:50 +02:00
|
|
|
Session.flush()
|
|
|
|
return user
|
|
|
|
|
2023-05-15 12:34:58 +02:00
|
|
|
# create a first alias mail to show user how to use when they login
|
|
|
|
alias = Alias.create_new(
|
|
|
|
user,
|
|
|
|
prefix="simplelogin-newsletter",
|
|
|
|
mailbox_id=mb.id,
|
|
|
|
note="This is your first alias. It's used to receive SimpleLogin communications "
|
|
|
|
"like new features announcements, newsletters.",
|
|
|
|
)
|
|
|
|
Session.flush()
|
|
|
|
|
|
|
|
user.newsletter_alias_id = alias.id
|
|
|
|
Session.flush()
|
|
|
|
|
2022-06-30 11:40:01 +02:00
|
|
|
if config.DISABLE_ONBOARDING:
|
2020-05-10 14:43:41 +02:00
|
|
|
LOG.d("Disable onboarding emails")
|
|
|
|
return user
|
|
|
|
|
2020-02-03 07:11:38 +01:00
|
|
|
# Schedule onboarding emails
|
|
|
|
Job.create(
|
2022-06-30 11:40:01 +02:00
|
|
|
name=config.JOB_ONBOARDING_1,
|
2020-02-03 07:11:38 +01:00
|
|
|
payload={"user_id": user.id},
|
|
|
|
run_at=arrow.now().shift(days=1),
|
|
|
|
)
|
2020-03-24 21:01:38 +01:00
|
|
|
Job.create(
|
2022-06-30 11:40:01 +02:00
|
|
|
name=config.JOB_ONBOARDING_2,
|
2020-03-24 21:01:38 +01:00
|
|
|
payload={"user_id": user.id},
|
|
|
|
run_at=arrow.now().shift(days=2),
|
|
|
|
)
|
2020-04-02 23:26:17 +02:00
|
|
|
Job.create(
|
2022-06-30 11:40:01 +02:00
|
|
|
name=config.JOB_ONBOARDING_4,
|
2020-04-02 23:26:17 +02:00
|
|
|
payload={"user_id": user.id},
|
2020-10-22 11:46:15 +02:00
|
|
|
run_at=arrow.now().shift(days=3),
|
2020-04-02 23:26:17 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.flush()
|
2020-02-03 07:11:38 +01:00
|
|
|
|
2019-07-12 10:34:15 +02:00
|
|
|
return user
|
|
|
|
|
2024-05-23 10:27:08 +02:00
|
|
|
@classmethod
|
|
|
|
def delete(cls, obj_id, commit=False):
|
|
|
|
# Internal import to avoid global import cycles
|
|
|
|
from app.events.event_dispatcher import EventDispatcher
|
|
|
|
from app.events.generated.event_pb2 import UserDeleted, EventContent
|
|
|
|
|
|
|
|
user: User = cls.get(obj_id)
|
|
|
|
EventDispatcher.send_event(user, EventContent(user_deleted=UserDeleted()))
|
|
|
|
|
2024-07-08 16:39:18 +02:00
|
|
|
# Manually delete all aliases for the user that is about to be deleted
|
|
|
|
from app.alias_utils import delete_alias
|
|
|
|
|
|
|
|
for alias in Alias.filter_by(user_id=user.id):
|
|
|
|
delete_alias(alias, user, AliasDeleteReason.UserHasBeenDeleted)
|
|
|
|
|
2024-05-23 10:27:08 +02:00
|
|
|
res = super(User, cls).delete(obj_id)
|
|
|
|
if commit:
|
|
|
|
Session.commit()
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
def get_active_subscription(
|
2023-05-15 12:34:58 +02:00
|
|
|
self, include_partner_subscription: bool = True
|
2022-06-20 14:34:20 +02:00
|
|
|
) -> Optional[
|
|
|
|
Union[
|
|
|
|
Subscription
|
|
|
|
| AppleSubscription
|
|
|
|
| ManualSubscription
|
|
|
|
| CoinbaseSubscription
|
|
|
|
| PartnerSubscription
|
|
|
|
]
|
|
|
|
]:
|
|
|
|
sub: Subscription = self.get_paddle_subscription()
|
2019-11-15 13:52:22 +01:00
|
|
|
if sub:
|
2022-06-20 14:34:20 +02:00
|
|
|
return sub
|
2019-11-15 13:52:22 +01:00
|
|
|
|
2020-04-19 10:58:32 +02:00
|
|
|
apple_sub: AppleSubscription = AppleSubscription.get_by(user_id=self.id)
|
|
|
|
if apple_sub and apple_sub.is_valid():
|
2022-06-20 14:34:20 +02:00
|
|
|
return apple_sub
|
2020-04-19 10:58:32 +02:00
|
|
|
|
2020-02-23 10:31:55 +01:00
|
|
|
manual_sub: ManualSubscription = ManualSubscription.get_by(user_id=self.id)
|
2020-12-13 19:08:06 +01:00
|
|
|
if manual_sub and manual_sub.is_active():
|
2022-06-20 14:34:20 +02:00
|
|
|
return manual_sub
|
2020-12-13 19:08:06 +01:00
|
|
|
|
|
|
|
coinbase_subscription: CoinbaseSubscription = CoinbaseSubscription.get_by(
|
|
|
|
user_id=self.id
|
|
|
|
)
|
|
|
|
if coinbase_subscription and coinbase_subscription.is_active():
|
2022-06-20 14:34:20 +02:00
|
|
|
return coinbase_subscription
|
2020-02-23 10:31:55 +01:00
|
|
|
|
2023-05-15 12:34:58 +02:00
|
|
|
if include_partner_subscription:
|
|
|
|
partner_sub: PartnerSubscription = PartnerSubscription.find_by_user_id(
|
|
|
|
self.id
|
|
|
|
)
|
|
|
|
if partner_sub and partner_sub.is_active():
|
|
|
|
return partner_sub
|
2022-06-09 10:19:49 +02:00
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
return None
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2023-05-26 15:33:55 +02:00
|
|
|
def get_active_subscription_end(
|
|
|
|
self, include_partner_subscription: bool = True
|
|
|
|
) -> Optional[arrow.Arrow]:
|
|
|
|
sub = self.get_active_subscription(
|
|
|
|
include_partner_subscription=include_partner_subscription
|
|
|
|
)
|
|
|
|
if isinstance(sub, Subscription):
|
|
|
|
return arrow.get(sub.next_bill_date)
|
|
|
|
if isinstance(sub, AppleSubscription):
|
|
|
|
return sub.expires_date
|
|
|
|
if isinstance(sub, ManualSubscription):
|
|
|
|
return sub.end_at
|
|
|
|
if isinstance(sub, CoinbaseSubscription):
|
|
|
|
return sub.end_at
|
|
|
|
return None
|
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
# region Billing
|
2023-05-15 12:34:58 +02:00
|
|
|
def lifetime_or_active_subscription(
|
|
|
|
self, include_partner_subscription: bool = True
|
|
|
|
) -> bool:
|
2022-06-20 14:34:20 +02:00
|
|
|
"""True if user has lifetime licence or active subscription"""
|
|
|
|
if self.lifetime:
|
2020-07-02 08:48:37 +02:00
|
|
|
return True
|
|
|
|
|
2023-05-15 12:34:58 +02:00
|
|
|
return self.get_active_subscription(include_partner_subscription) is not None
|
2020-07-02 08:48:37 +02:00
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
def is_paid(self) -> bool:
|
|
|
|
"""same as _lifetime_or_active_subscription but not include free manual subscription"""
|
|
|
|
sub = self.get_active_subscription()
|
|
|
|
if sub is None:
|
|
|
|
return False
|
2020-12-13 19:08:06 +01:00
|
|
|
|
2022-07-04 11:05:42 +02:00
|
|
|
if isinstance(sub, ManualSubscription) and sub.is_giveaway:
|
2022-06-20 14:34:20 +02:00
|
|
|
return False
|
2020-07-02 08:48:37 +02:00
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
return True
|
2020-07-02 08:48:37 +02:00
|
|
|
|
2024-02-22 17:38:34 +01:00
|
|
|
def is_active(self) -> bool:
|
|
|
|
if self.delete_on is None:
|
|
|
|
return True
|
|
|
|
return self.delete_on < arrow.now()
|
|
|
|
|
2020-01-30 04:52:56 +01:00
|
|
|
def in_trial(self):
|
|
|
|
"""return True if user does not have lifetime licence or an active subscription AND is in trial period"""
|
2021-08-21 15:55:22 +02:00
|
|
|
if self.lifetime_or_active_subscription():
|
2020-01-30 04:52:56 +01:00
|
|
|
return False
|
|
|
|
|
2020-01-30 09:08:26 +01:00
|
|
|
if self.trial_end and arrow.now() < self.trial_end:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
2020-01-30 04:52:56 +01:00
|
|
|
|
2020-04-13 20:49:35 +02:00
|
|
|
def should_show_upgrade_button(self):
|
2021-08-21 15:55:22 +02:00
|
|
|
if self.lifetime_or_active_subscription():
|
2020-03-05 09:13:28 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
2023-05-15 12:34:58 +02:00
|
|
|
def is_premium(self, include_partner_subscription: bool = True) -> bool:
|
2020-01-30 04:52:56 +01:00
|
|
|
"""
|
|
|
|
user is premium if they:
|
|
|
|
- have a lifetime deal or
|
|
|
|
- in trial period or
|
|
|
|
- active subscription
|
|
|
|
"""
|
2023-05-15 12:34:58 +02:00
|
|
|
if self.lifetime_or_active_subscription(include_partner_subscription):
|
2020-01-30 04:52:56 +01:00
|
|
|
return True
|
|
|
|
|
2020-01-30 07:20:32 +01:00
|
|
|
if self.trial_end and arrow.now() < self.trial_end:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
2020-01-30 04:52:56 +01:00
|
|
|
|
2021-01-08 18:53:01 +01:00
|
|
|
@property
|
|
|
|
def upgrade_channel(self) -> str:
|
2021-11-29 16:26:41 +01:00
|
|
|
"""Used on admin dashboard"""
|
|
|
|
# user can have multiple subscription channel
|
|
|
|
channels = []
|
2021-01-08 18:53:01 +01:00
|
|
|
if self.lifetime:
|
2021-11-29 16:26:41 +01:00
|
|
|
channels.append("Lifetime")
|
2021-01-08 18:53:01 +01:00
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
sub: Subscription = self.get_paddle_subscription()
|
2021-01-08 18:53:01 +01:00
|
|
|
if sub:
|
2021-06-05 17:20:42 +02:00
|
|
|
if sub.cancelled:
|
2021-11-29 16:46:03 +01:00
|
|
|
channels.append(
|
2022-09-02 10:39:53 +02:00
|
|
|
f"""Cancelled Paddle Subscription <a href="https://vendors.paddle.com/subscriptions/customers/manage/{sub.subscription_id}">{sub.subscription_id}</a> {sub.plan_name()} ends at {sub.next_bill_date}"""
|
2021-11-29 16:46:03 +01:00
|
|
|
)
|
2021-06-05 17:20:42 +02:00
|
|
|
else:
|
2021-11-29 16:46:03 +01:00
|
|
|
channels.append(
|
2022-09-02 10:39:53 +02:00
|
|
|
f"""Active Paddle Subscription <a href="https://vendors.paddle.com/subscriptions/customers/manage/{sub.subscription_id}">{sub.subscription_id}</a> {sub.plan_name()}, renews at {sub.next_bill_date}"""
|
2021-11-29 16:46:03 +01:00
|
|
|
)
|
2021-01-08 18:53:01 +01:00
|
|
|
|
|
|
|
apple_sub: AppleSubscription = AppleSubscription.get_by(user_id=self.id)
|
|
|
|
if apple_sub and apple_sub.is_valid():
|
2021-11-30 10:33:31 +01:00
|
|
|
channels.append(f"Apple Subscription {apple_sub.expires_date.humanize()}")
|
2021-01-08 18:53:01 +01:00
|
|
|
|
|
|
|
manual_sub: ManualSubscription = ManualSubscription.get_by(user_id=self.id)
|
|
|
|
if manual_sub and manual_sub.is_active():
|
|
|
|
mode = "Giveaway" if manual_sub.is_giveaway else "Paid"
|
2021-11-30 10:33:31 +01:00
|
|
|
channels.append(
|
|
|
|
f"Manual Subscription {manual_sub.comment} {mode} {manual_sub.end_at.humanize()}"
|
|
|
|
)
|
2021-01-08 18:53:01 +01:00
|
|
|
|
|
|
|
coinbase_subscription: CoinbaseSubscription = CoinbaseSubscription.get_by(
|
|
|
|
user_id=self.id
|
|
|
|
)
|
|
|
|
if coinbase_subscription and coinbase_subscription.is_active():
|
2021-11-29 16:46:03 +01:00
|
|
|
channels.append(
|
|
|
|
f"Coinbase Subscription ends {coinbase_subscription.end_at.humanize()}"
|
|
|
|
)
|
2021-01-08 18:53:01 +01:00
|
|
|
|
2022-08-01 20:49:05 +02:00
|
|
|
r = (
|
|
|
|
Session.query(PartnerSubscription, PartnerUser, Partner)
|
|
|
|
.filter(
|
|
|
|
PartnerSubscription.partner_user_id == PartnerUser.id,
|
|
|
|
PartnerUser.user_id == self.id,
|
|
|
|
Partner.id == PartnerUser.partner_id,
|
|
|
|
)
|
|
|
|
.first()
|
|
|
|
)
|
|
|
|
if r and r[0].is_active():
|
|
|
|
channels.append(
|
|
|
|
f"Subscription via {r[2].name} partner , ends {r[0].end_at.humanize()}"
|
|
|
|
)
|
|
|
|
|
2021-11-29 16:26:41 +01:00
|
|
|
return ".\n".join(channels)
|
|
|
|
|
2021-11-29 11:35:28 +01:00
|
|
|
# endregion
|
2021-03-26 12:14:48 +01:00
|
|
|
|
2022-07-20 11:09:22 +02:00
|
|
|
def max_alias_for_free_account(self) -> int:
|
|
|
|
if (
|
|
|
|
self.FLAG_FREE_OLD_ALIAS_LIMIT
|
|
|
|
== self.flags & self.FLAG_FREE_OLD_ALIAS_LIMIT
|
|
|
|
):
|
|
|
|
return config.MAX_NB_EMAIL_OLD_FREE_PLAN
|
|
|
|
else:
|
|
|
|
return config.MAX_NB_EMAIL_FREE_PLAN
|
|
|
|
|
2020-01-30 04:52:56 +01:00
|
|
|
def can_create_new_alias(self) -> bool:
|
2021-04-09 12:40:55 +02:00
|
|
|
"""
|
|
|
|
Whether user can create a new alias. User can't create a new alias if
|
|
|
|
- has more than 15 aliases in the free plan, *even in the free trial*
|
|
|
|
"""
|
2024-02-22 17:38:34 +01:00
|
|
|
if not self.is_active():
|
|
|
|
return False
|
|
|
|
|
2022-04-27 16:05:40 +02:00
|
|
|
if self.disabled:
|
|
|
|
return False
|
|
|
|
|
2021-08-21 15:55:22 +02:00
|
|
|
if self.lifetime_or_active_subscription():
|
2019-07-06 23:25:52 +02:00
|
|
|
return True
|
2021-04-09 12:40:55 +02:00
|
|
|
else:
|
2022-06-30 11:40:01 +02:00
|
|
|
return (
|
2022-07-20 11:09:22 +02:00
|
|
|
Alias.filter_by(user_id=self.id).count()
|
|
|
|
< self.max_alias_for_free_account()
|
2022-06-30 11:40:01 +02:00
|
|
|
)
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2023-09-10 22:11:50 +02:00
|
|
|
def can_send_or_receive(self) -> bool:
|
|
|
|
if self.disabled:
|
|
|
|
LOG.i(f"User {self} is disabled. Cannot receive or send emails")
|
|
|
|
return False
|
|
|
|
if self.delete_on is not None:
|
|
|
|
LOG.i(
|
|
|
|
f"User {self} is scheduled to be deleted. Cannot receive or send emails"
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
def profile_picture_url(self):
|
|
|
|
if self.profile_picture_id:
|
|
|
|
return self.profile_picture.get_url()
|
2019-07-22 17:28:31 +02:00
|
|
|
else:
|
|
|
|
return url_for("static", filename="default-avatar.png")
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-12-08 17:01:09 +01:00
|
|
|
def suggested_emails(self, website_name) -> (str, [str]):
|
2022-02-06 15:25:53 +01:00
|
|
|
"""return suggested email and other email choices"""
|
2019-12-08 17:01:09 +01:00
|
|
|
website_name = convert_to_id(website_name)
|
|
|
|
|
2020-05-02 12:28:44 +02:00
|
|
|
all_aliases = [
|
|
|
|
ge.email for ge in Alias.filter_by(user_id=self.id, enabled=True)
|
|
|
|
]
|
2019-12-22 17:27:55 +01:00
|
|
|
if self.can_create_new_alias():
|
2020-03-17 11:51:40 +01:00
|
|
|
suggested_alias = Alias.create_new(self, prefix=website_name).email
|
2019-07-22 18:57:35 +02:00
|
|
|
else:
|
|
|
|
# pick an email from the list of gen emails
|
2020-03-17 11:51:40 +01:00
|
|
|
suggested_alias = random.choice(all_aliases)
|
2019-07-22 18:57:35 +02:00
|
|
|
|
|
|
|
return (
|
2020-03-17 11:51:40 +01:00
|
|
|
suggested_alias,
|
|
|
|
list(set(all_aliases).difference({suggested_alias})),
|
2019-07-22 18:57:35 +02:00
|
|
|
)
|
|
|
|
|
2019-07-22 21:28:17 +02:00
|
|
|
def suggested_names(self) -> (str, [str]):
|
2022-02-06 15:25:53 +01:00
|
|
|
"""return suggested name and other name choices"""
|
2019-07-22 21:28:17 +02:00
|
|
|
other_name = convert_to_id(self.name)
|
|
|
|
|
|
|
|
return self.name, [other_name, "Anonymous", "whoami"]
|
|
|
|
|
2019-08-16 11:57:19 +02:00
|
|
|
def get_name_initial(self) -> str:
|
2021-01-15 11:21:45 +01:00
|
|
|
if not self.name:
|
|
|
|
return ""
|
2019-08-16 11:57:19 +02:00
|
|
|
names = self.name.split(" ")
|
|
|
|
return "".join([n[0].upper() for n in names if n])
|
|
|
|
|
2022-06-20 14:34:20 +02:00
|
|
|
def get_paddle_subscription(self) -> Optional["Subscription"]:
|
2020-12-13 19:08:06 +01:00
|
|
|
"""return *active* Paddle subscription
|
|
|
|
Return None if the subscription is already expired
|
2020-01-01 19:46:35 +01:00
|
|
|
TODO: support user unsubscribe and re-subscribe
|
|
|
|
"""
|
2019-11-14 14:52:33 +01:00
|
|
|
sub = Subscription.get_by(user_id=self.id)
|
2020-03-08 11:36:09 +01:00
|
|
|
|
2020-09-24 09:34:35 +02:00
|
|
|
if sub:
|
2022-05-11 17:24:52 +02:00
|
|
|
# grace period is 14 days
|
2022-05-11 19:03:27 +02:00
|
|
|
# sub is active until the next billing_date + PADDLE_SUBSCRIPTION_GRACE_DAYS
|
|
|
|
if (
|
|
|
|
sub.next_bill_date
|
|
|
|
>= arrow.now().shift(days=-PADDLE_SUBSCRIPTION_GRACE_DAYS).date()
|
|
|
|
):
|
2020-01-01 19:46:35 +01:00
|
|
|
return sub
|
2020-03-05 09:13:28 +01:00
|
|
|
# past subscription, user is considered not having a subscription = free plan
|
|
|
|
else:
|
2020-01-01 19:46:35 +01:00
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return sub
|
|
|
|
|
2020-12-31 12:50:04 +01:00
|
|
|
def verified_custom_domains(self) -> List["CustomDomain"]:
|
2024-02-08 15:36:06 +01:00
|
|
|
return (
|
|
|
|
CustomDomain.filter_by(user_id=self.id, ownership_verified=True)
|
|
|
|
.order_by(CustomDomain.domain.asc())
|
|
|
|
.all()
|
|
|
|
)
|
2019-12-02 01:13:39 +01:00
|
|
|
|
2020-04-25 13:38:05 +02:00
|
|
|
def mailboxes(self) -> List["Mailbox"]:
|
|
|
|
"""list of mailbox that user own"""
|
2020-02-28 18:03:35 +01:00
|
|
|
mailboxes = []
|
2020-02-23 07:41:27 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
for mailbox in Mailbox.filter_by(user_id=self.id, verified=True):
|
2020-04-25 13:38:05 +02:00
|
|
|
mailboxes.append(mailbox)
|
2020-02-23 07:41:27 +01:00
|
|
|
|
|
|
|
return mailboxes
|
|
|
|
|
2020-04-12 20:14:49 +02:00
|
|
|
def nb_directory(self):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Directory.filter_by(user_id=self.id).count()
|
2020-04-12 20:14:49 +02:00
|
|
|
|
2020-06-25 13:04:27 +02:00
|
|
|
def has_custom_domain(self):
|
|
|
|
return CustomDomain.filter_by(user_id=self.id, verified=True).count() > 0
|
|
|
|
|
2024-09-17 10:30:55 +02:00
|
|
|
def custom_domains(self) -> List["CustomDomain"]:
|
2020-06-25 13:04:27 +02:00
|
|
|
return CustomDomain.filter_by(user_id=self.id, verified=True).all()
|
|
|
|
|
2023-04-06 11:07:13 +02:00
|
|
|
def available_domains_for_random_alias(
|
|
|
|
self, alias_options: Optional[AliasOptions] = None
|
|
|
|
) -> List[Tuple[bool, str]]:
|
2020-07-04 23:24:32 +02:00
|
|
|
"""Return available domains for user to create random aliases
|
|
|
|
Each result record contains:
|
2020-10-15 16:21:31 +02:00
|
|
|
- whether the domain belongs to SimpleLogin
|
2020-07-04 23:24:32 +02:00
|
|
|
- the domain
|
|
|
|
"""
|
|
|
|
res = []
|
2024-07-23 16:17:23 +02:00
|
|
|
for domain in self.get_sl_domains(alias_options=alias_options):
|
|
|
|
res.append((True, domain.domain))
|
2020-07-04 23:24:32 +02:00
|
|
|
|
2020-10-15 16:21:31 +02:00
|
|
|
for custom_domain in self.verified_custom_domains():
|
2020-07-04 23:24:32 +02:00
|
|
|
res.append((False, custom_domain.domain))
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
def default_random_alias_domain(self) -> str:
|
|
|
|
"""return the domain used for the random alias"""
|
2020-12-31 14:06:32 +01:00
|
|
|
if self.default_alias_custom_domain_id:
|
|
|
|
custom_domain = CustomDomain.get(self.default_alias_custom_domain_id)
|
2020-07-04 23:24:32 +02:00
|
|
|
# sanity check
|
|
|
|
if (
|
|
|
|
not custom_domain
|
|
|
|
or not custom_domain.verified
|
|
|
|
or custom_domain.user_id != self.id
|
|
|
|
):
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("Problem with %s default random alias domain", self)
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.FIRST_ALIAS_DOMAIN
|
2020-07-04 23:24:32 +02:00
|
|
|
|
|
|
|
return custom_domain.domain
|
|
|
|
|
2020-12-31 14:14:56 +01:00
|
|
|
if self.default_alias_public_domain_id:
|
|
|
|
sl_domain = SLDomain.get(self.default_alias_public_domain_id)
|
2020-07-04 23:24:32 +02:00
|
|
|
# sanity check
|
2020-10-15 16:52:38 +02:00
|
|
|
if not sl_domain:
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.e("Problem with %s public random alias domain", self)
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.FIRST_ALIAS_DOMAIN
|
2020-07-04 23:24:32 +02:00
|
|
|
|
2020-10-15 16:52:38 +02:00
|
|
|
if sl_domain.premium_only and not self.is_premium():
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w(
|
2020-11-01 09:37:09 +01:00
|
|
|
"%s is not premium and cannot use %s. Reset default random alias domain setting",
|
|
|
|
self,
|
|
|
|
sl_domain,
|
|
|
|
)
|
2020-12-31 14:06:32 +01:00
|
|
|
self.default_alias_custom_domain_id = None
|
2020-12-31 14:14:56 +01:00
|
|
|
self.default_alias_public_domain_id = None
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.FIRST_ALIAS_DOMAIN
|
2020-10-15 16:21:31 +02:00
|
|
|
|
2020-10-15 16:52:38 +02:00
|
|
|
return sl_domain.domain
|
2020-07-04 23:24:32 +02:00
|
|
|
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.FIRST_ALIAS_DOMAIN
|
2020-07-04 23:24:32 +02:00
|
|
|
|
2020-07-04 22:46:09 +02:00
|
|
|
def fido_enabled(self) -> bool:
|
|
|
|
if self.fido_uuid is not None:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def two_factor_authentication_enabled(self) -> bool:
|
|
|
|
return self.enable_otp or self.fido_enabled()
|
|
|
|
|
2022-12-19 09:23:53 +01:00
|
|
|
def get_communication_email(self) -> (Optional[str], str, bool):
|
2020-10-22 10:44:05 +02:00
|
|
|
"""
|
|
|
|
Return
|
|
|
|
- the email that user uses to receive email communication. None if user unsubscribes from newsletter
|
|
|
|
- the unsubscribe URL
|
|
|
|
- whether the unsubscribe method is via sending email (mailto:) or Http POST
|
|
|
|
"""
|
2021-11-20 19:42:49 +01:00
|
|
|
if self.notification and self.activated and not self.disabled:
|
2020-09-12 14:31:31 +02:00
|
|
|
if self.newsletter_alias_id:
|
|
|
|
alias = Alias.get(self.newsletter_alias_id)
|
|
|
|
if alias.enabled:
|
2022-06-30 11:40:01 +02:00
|
|
|
unsub = UnsubscribeEncoder.encode(
|
|
|
|
UnsubscribeAction.DisableAlias, alias.id
|
|
|
|
)
|
2022-12-19 09:23:53 +01:00
|
|
|
return alias.email, unsub.link, unsub.via_email
|
2020-10-22 10:44:05 +02:00
|
|
|
# alias disabled -> user doesn't want to receive newsletter
|
2020-09-12 14:31:31 +02:00
|
|
|
else:
|
2022-12-13 16:59:14 +01:00
|
|
|
return None, "", False
|
2020-09-12 14:31:31 +02:00
|
|
|
else:
|
2020-10-22 10:44:05 +02:00
|
|
|
# do not handle http POST unsubscribe
|
2022-06-30 11:40:01 +02:00
|
|
|
if config.UNSUBSCRIBER:
|
2020-10-22 10:44:05 +02:00
|
|
|
# use * as suffix instead of = as for alias unsubscribe
|
2022-06-30 11:40:01 +02:00
|
|
|
return (
|
|
|
|
self.email,
|
|
|
|
UnsubscribeEncoder.encode_mailto(
|
|
|
|
UnsubscribeAction.UnsubscribeNewsletter, self.id
|
|
|
|
),
|
|
|
|
True,
|
|
|
|
)
|
2020-09-12 14:31:31 +02:00
|
|
|
|
2022-12-13 16:59:14 +01:00
|
|
|
return None, "", False
|
2020-09-12 14:31:31 +02:00
|
|
|
|
2023-04-06 11:07:13 +02:00
|
|
|
def available_sl_domains(
|
|
|
|
self, alias_options: Optional[AliasOptions] = None
|
|
|
|
) -> [str]:
|
2020-10-15 16:21:31 +02:00
|
|
|
"""
|
|
|
|
Return all SimpleLogin domains that user can use when creating a new alias, including:
|
|
|
|
- SimpleLogin public domains, available for all users (ALIAS_DOMAIN)
|
|
|
|
- SimpleLogin premium domains, only available for Premium accounts (PREMIUM_ALIAS_DOMAIN)
|
|
|
|
"""
|
2023-04-06 11:07:13 +02:00
|
|
|
return [
|
|
|
|
sl_domain.domain
|
|
|
|
for sl_domain in self.get_sl_domains(alias_options=alias_options)
|
|
|
|
]
|
2020-10-20 16:44:22 +02:00
|
|
|
|
2023-04-04 15:21:51 +02:00
|
|
|
def get_sl_domains(
|
2023-04-06 11:07:13 +02:00
|
|
|
self, alias_options: Optional[AliasOptions] = None
|
2023-04-04 15:21:51 +02:00
|
|
|
) -> list["SLDomain"]:
|
2023-04-06 11:07:13 +02:00
|
|
|
if alias_options is None:
|
|
|
|
alias_options = AliasOptions()
|
2023-09-13 18:12:47 +02:00
|
|
|
top_conds = [SLDomain.hidden == False] # noqa: E712
|
|
|
|
or_conds = [] # noqa:E711
|
2023-06-06 15:55:10 +02:00
|
|
|
if self.default_alias_public_domain_id is not None:
|
2023-09-13 18:12:47 +02:00
|
|
|
default_domain_conds = [SLDomain.id == self.default_alias_public_domain_id]
|
|
|
|
if not self.is_premium():
|
|
|
|
default_domain_conds.append(
|
|
|
|
SLDomain.premium_only == False # noqa: E712
|
|
|
|
)
|
|
|
|
or_conds.append(and_(*default_domain_conds).self_group())
|
2023-04-06 11:07:13 +02:00
|
|
|
if alias_options.show_partner_domains is not None:
|
2023-04-04 15:21:51 +02:00
|
|
|
partner_user = PartnerUser.filter_by(
|
2023-04-06 11:07:13 +02:00
|
|
|
user_id=self.id, partner_id=alias_options.show_partner_domains.id
|
2023-04-04 15:21:51 +02:00
|
|
|
).first()
|
|
|
|
if partner_user is not None:
|
2023-09-13 18:12:47 +02:00
|
|
|
partner_domain_cond = [SLDomain.partner_id == partner_user.partner_id]
|
|
|
|
if alias_options.show_partner_premium is None:
|
|
|
|
alias_options.show_partner_premium = self.is_premium()
|
|
|
|
if not alias_options.show_partner_premium:
|
|
|
|
partner_domain_cond.append(
|
|
|
|
SLDomain.premium_only == False # noqa: E712
|
|
|
|
)
|
|
|
|
or_conds.append(and_(*partner_domain_cond).self_group())
|
2023-04-06 11:07:13 +02:00
|
|
|
if alias_options.show_sl_domains:
|
2023-09-13 18:12:47 +02:00
|
|
|
sl_conds = [SLDomain.partner_id == None] # noqa: E711
|
|
|
|
if not self.is_premium():
|
|
|
|
sl_conds.append(SLDomain.premium_only == False) # noqa: E712
|
|
|
|
or_conds.append(and_(*sl_conds).self_group())
|
|
|
|
top_conds.append(or_(*or_conds))
|
|
|
|
query = Session.query(SLDomain).filter(*top_conds).order_by(SLDomain.order)
|
2023-04-04 15:21:51 +02:00
|
|
|
return query.all()
|
2020-10-15 16:21:31 +02:00
|
|
|
|
2023-04-06 11:07:13 +02:00
|
|
|
def available_alias_domains(
|
|
|
|
self, alias_options: Optional[AliasOptions] = None
|
|
|
|
) -> [str]:
|
2020-10-15 16:21:31 +02:00
|
|
|
"""return all domains that user can use when creating a new alias, including:
|
|
|
|
- SimpleLogin public domains, available for all users (ALIAS_DOMAIN)
|
|
|
|
- SimpleLogin premium domains, only available for Premium accounts (PREMIUM_ALIAS_DOMAIN)
|
|
|
|
- Verified custom domains
|
|
|
|
|
|
|
|
"""
|
2024-07-23 16:17:23 +02:00
|
|
|
domains = [
|
|
|
|
sl_domain.domain
|
|
|
|
for sl_domain in self.get_sl_domains(alias_options=alias_options)
|
|
|
|
]
|
2020-10-15 16:21:31 +02:00
|
|
|
|
|
|
|
for custom_domain in self.verified_custom_domains():
|
|
|
|
domains.append(custom_domain.domain)
|
|
|
|
|
2020-10-15 17:02:54 +02:00
|
|
|
# can have duplicate where a "root" user has a domain that's also listed in SL domains
|
|
|
|
return list(set(domains))
|
2020-10-15 16:21:31 +02:00
|
|
|
|
2021-04-01 14:09:16 +02:00
|
|
|
def should_show_app_page(self) -> bool:
|
|
|
|
"""whether to show the app page"""
|
|
|
|
return (
|
|
|
|
# when user has used the "Sign in with SL" button before
|
2021-10-12 14:36:47 +02:00
|
|
|
ClientUser.filter(ClientUser.user_id == self.id).count()
|
2021-04-01 14:09:16 +02:00
|
|
|
# or when user has created an app
|
2021-10-12 14:36:47 +02:00
|
|
|
+ Client.filter(Client.user_id == self.id).count()
|
2021-04-01 14:09:16 +02:00
|
|
|
> 0
|
|
|
|
)
|
|
|
|
|
2023-03-28 22:33:28 +02:00
|
|
|
def get_random_alias_suffix(self, custom_domain: Optional["CustomDomain"] = None):
|
2021-06-27 17:51:13 +02:00
|
|
|
"""Get random suffix for an alias based on user's preference.
|
|
|
|
|
2023-03-28 22:33:28 +02:00
|
|
|
Use a shorter suffix in case of custom domain
|
2021-06-27 17:51:13 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
str: the random suffix generated
|
|
|
|
"""
|
|
|
|
if self.random_alias_suffix == AliasSuffixEnum.random_string.value:
|
2022-06-30 11:40:01 +02:00
|
|
|
return random_string(config.ALIAS_RANDOM_SUFFIX_LENGTH, include_digits=True)
|
2023-03-28 22:33:28 +02:00
|
|
|
|
|
|
|
if custom_domain is None:
|
|
|
|
return random_words(1, 3)
|
|
|
|
|
|
|
|
return random_words(1)
|
2021-06-27 17:51:13 +02:00
|
|
|
|
2024-01-16 14:51:01 +01:00
|
|
|
def can_create_contacts(self) -> bool:
|
|
|
|
if self.is_premium():
|
|
|
|
return True
|
2024-09-27 16:04:32 +02:00
|
|
|
if self.flags & User.FLAG_DISABLE_CREATE_CONTACTS == 0:
|
2024-01-16 14:51:01 +01:00
|
|
|
return True
|
|
|
|
return not config.DISABLE_CREATE_CONTACTS_FOR_FREE_USERS
|
|
|
|
|
2024-06-28 15:34:16 +02:00
|
|
|
def has_used_alias_from_partner(self) -> bool:
|
|
|
|
return (
|
|
|
|
self.flags
|
|
|
|
& (User.FLAG_CREATED_ALIAS_FROM_PARTNER | User.FLAG_CREATED_FROM_PARTNER)
|
|
|
|
> 0
|
|
|
|
)
|
|
|
|
|
2019-08-30 22:12:31 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<User {self.id} {self.name} {self.email}>"
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-17 22:17:23 +02:00
|
|
|
def _expiration_1h():
|
|
|
|
return arrow.now().shift(hours=1)
|
|
|
|
|
|
|
|
|
2019-11-18 19:32:58 +01:00
|
|
|
def _expiration_12h():
|
|
|
|
return arrow.now().shift(hours=12)
|
|
|
|
|
|
|
|
|
2019-08-17 22:17:23 +02:00
|
|
|
def _expiration_5m():
|
|
|
|
return arrow.now().shift(minutes=5)
|
|
|
|
|
|
|
|
|
2020-03-14 16:07:34 +01:00
|
|
|
def _expiration_7d():
|
|
|
|
return arrow.now().shift(days=7)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class ActivationCode(Base, ModelMixin):
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
"""For activate user account"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "activation_code"
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
|
|
|
|
|
|
|
expired = sa.Column(ArrowType, nullable=False, default=_expiration_1h)
|
2019-08-17 22:21:32 +02:00
|
|
|
|
|
|
|
def is_expired(self):
|
|
|
|
return self.expired < arrow.now()
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class ResetPasswordCode(Base, ModelMixin):
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
"""For resetting password"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "reset_password_code"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
expired = sa.Column(ArrowType, nullable=False, default=_expiration_1h)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-17 22:21:32 +02:00
|
|
|
def is_expired(self):
|
|
|
|
return self.expired < arrow.now()
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class SocialAuth(Base, ModelMixin):
|
2020-02-27 16:15:22 +01:00
|
|
|
"""Store how user authenticates with social login"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "social_auth"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
2020-02-27 16:15:22 +01:00
|
|
|
|
|
|
|
# name of the social login used, could be facebook, google or github
|
2021-10-12 14:36:47 +02:00
|
|
|
social = sa.Column(sa.String(128), nullable=False)
|
2020-02-27 16:15:22 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__table_args__ = (sa.UniqueConstraint("user_id", "social", name="uq_social_auth"),)
|
2020-02-27 16:15:22 +01:00
|
|
|
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
# <<< OAUTH models >>>
|
|
|
|
|
|
|
|
|
|
|
|
def generate_oauth_client_id(client_name) -> str:
|
|
|
|
oauth_client_id = convert_to_id(client_name) + "-" + random_string()
|
|
|
|
|
|
|
|
# check that the client does not exist yet
|
|
|
|
if not Client.get_by(oauth_client_id=oauth_client_id):
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.d("generate oauth_client_id %s", oauth_client_id)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
return oauth_client_id
|
|
|
|
|
|
|
|
# Rerun the function
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("client_id %s already exists, generate a new client_id", oauth_client_id)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
return generate_oauth_client_id(client_name)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class MfaBrowser(Base, ModelMixin):
|
|
|
|
__tablename__ = "mfa_browser"
|
2020-05-22 16:14:52 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
token = sa.Column(sa.String(64), default=False, unique=True, nullable=False)
|
|
|
|
expires = sa.Column(ArrowType, default=False, nullable=False)
|
|
|
|
|
|
|
|
user = orm.relationship(User)
|
2020-05-22 16:14:52 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create_new(cls, user, token_length=64) -> "MfaBrowser":
|
2020-05-22 16:50:03 +02:00
|
|
|
found = False
|
|
|
|
while not found:
|
|
|
|
token = random_string(token_length)
|
|
|
|
|
|
|
|
if not cls.get_by(token=token):
|
|
|
|
found = True
|
|
|
|
|
2020-05-22 16:14:52 +02:00
|
|
|
return MfaBrowser.create(
|
2020-08-27 10:20:48 +02:00
|
|
|
user_id=user.id,
|
|
|
|
token=token,
|
|
|
|
expires=arrow.now().shift(days=30),
|
2020-05-22 16:14:52 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def delete(cls, token):
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter(cls.token == token).delete()
|
|
|
|
Session.commit()
|
2020-05-22 16:14:52 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def delete_expired(cls):
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter(cls.expires < arrow.now()).delete()
|
|
|
|
Session.commit()
|
2020-05-22 16:14:52 +02:00
|
|
|
|
|
|
|
def is_expired(self):
|
|
|
|
return self.expires < arrow.now()
|
|
|
|
|
|
|
|
def reset_expire(self):
|
|
|
|
self.expires = arrow.now().shift(days=30)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Client(Base, ModelMixin):
|
|
|
|
__tablename__ = "client"
|
|
|
|
oauth_client_id = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
oauth_client_secret = sa.Column(sa.String(128), nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(128), nullable=False)
|
|
|
|
home_url = sa.Column(sa.String(1024))
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
# user who created this client
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
icon_id = sa.Column(sa.ForeignKey(File.id), nullable=True)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-04-01 10:50:11 +02:00
|
|
|
# an app needs to be approved by SimpleLogin team
|
2021-10-12 14:36:47 +02:00
|
|
|
approved = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
|
|
|
description = sa.Column(sa.Text, nullable=True)
|
2021-04-01 10:50:11 +02:00
|
|
|
|
2021-10-26 11:55:27 +02:00
|
|
|
# a referral can be attached to a client
|
|
|
|
# so all users who sign up via the authorize screen are counted towards this referral
|
2021-10-26 12:06:49 +02:00
|
|
|
referral_id = sa.Column(
|
|
|
|
sa.ForeignKey("referral.id", ondelete="SET NULL"), nullable=True
|
|
|
|
)
|
2021-10-26 11:55:27 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
icon = orm.relationship(File)
|
|
|
|
user = orm.relationship(User)
|
2021-10-26 11:55:27 +02:00
|
|
|
referral = orm.relationship("Referral")
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
def nb_user(self):
|
|
|
|
return ClientUser.filter_by(client_id=self.id).count()
|
|
|
|
|
2019-07-03 12:13:28 +02:00
|
|
|
def get_scopes(self) -> [Scope]:
|
2019-07-03 11:47:42 +02:00
|
|
|
# todo: client can choose which scopes they want to have access
|
2019-07-03 12:13:28 +02:00
|
|
|
return [Scope.NAME, Scope.EMAIL, Scope.AVATAR_URL]
|
2019-07-03 11:47:42 +02:00
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
@classmethod
|
|
|
|
def create_new(cls, name, user_id) -> "Client":
|
|
|
|
# generate a client-id
|
|
|
|
oauth_client_id = generate_oauth_client_id(name)
|
|
|
|
oauth_client_secret = random_string(40)
|
|
|
|
client = Client.create(
|
|
|
|
name=name,
|
|
|
|
oauth_client_id=oauth_client_id,
|
|
|
|
oauth_client_secret=oauth_client_secret,
|
|
|
|
user_id=user_id,
|
|
|
|
)
|
|
|
|
|
|
|
|
return client
|
|
|
|
|
|
|
|
def get_icon_url(self):
|
|
|
|
if self.icon_id:
|
|
|
|
return self.icon.get_url()
|
|
|
|
else:
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.URL + "/static/default-icon.svg"
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-16 12:56:13 +02:00
|
|
|
def last_user_login(self) -> "ClientUser":
|
|
|
|
client_user = (
|
2021-10-12 14:36:47 +02:00
|
|
|
ClientUser.filter(ClientUser.client_id == self.id)
|
2019-12-28 01:03:59 +01:00
|
|
|
.order_by(ClientUser.updated_at)
|
|
|
|
.first()
|
2019-08-16 12:56:13 +02:00
|
|
|
)
|
|
|
|
if client_user:
|
|
|
|
return client_user
|
|
|
|
return None
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class RedirectUri(Base, ModelMixin):
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
"""Valid redirect uris for a client"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "redirect_uri"
|
|
|
|
|
|
|
|
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
|
|
|
uri = sa.Column(sa.String(1024), nullable=False)
|
|
|
|
|
|
|
|
client = orm.relationship(Client, backref="redirect_uris")
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AuthorizationCode(Base, ModelMixin):
|
|
|
|
__tablename__ = "authorization_code"
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
scope = sa.Column(sa.String(128))
|
|
|
|
redirect_uri = sa.Column(sa.String(1024))
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-11 11:59:04 +02:00
|
|
|
# what is the input response_type, e.g. "code", "code,id_token", ...
|
2021-10-12 14:36:47 +02:00
|
|
|
response_type = sa.Column(sa.String(128))
|
2019-08-11 11:59:04 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nonce = sa.Column(sa.Text, nullable=True, default=None, server_default=text("NULL"))
|
2021-04-01 12:35:21 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User, lazy=False)
|
|
|
|
client = orm.relationship(Client, lazy=False)
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
expired = sa.Column(ArrowType, nullable=False, default=_expiration_5m)
|
2019-08-17 22:17:23 +02:00
|
|
|
|
|
|
|
def is_expired(self):
|
|
|
|
return self.expired < arrow.now()
|
|
|
|
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class OauthToken(Base, ModelMixin):
|
|
|
|
__tablename__ = "oauth_token"
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
access_token = sa.Column(sa.String(128), unique=True)
|
|
|
|
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
|
|
|
|
scope = sa.Column(sa.String(128))
|
|
|
|
redirect_uri = sa.Column(sa.String(1024))
|
2019-07-01 17:18:12 +02:00
|
|
|
|
2019-08-11 11:59:04 +02:00
|
|
|
# what is the input response_type, e.g. "token", "token,id_token", ...
|
2021-10-12 14:36:47 +02:00
|
|
|
response_type = sa.Column(sa.String(128))
|
2019-08-11 11:59:04 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
|
|
|
client = orm.relationship(Client)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
expired = sa.Column(ArrowType, nullable=False, default=_expiration_1h)
|
2019-08-17 22:17:23 +02:00
|
|
|
|
|
|
|
def is_expired(self):
|
|
|
|
return self.expired < arrow.now()
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2023-04-20 12:14:53 +02:00
|
|
|
def available_sl_email(email: str) -> bool:
|
|
|
|
if (
|
|
|
|
Alias.get_by(email=email)
|
|
|
|
or Contact.get_by(reply_email=email)
|
|
|
|
or DeletedAlias.get_by(email=email)
|
|
|
|
):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def generate_random_alias_email(
|
2020-06-25 13:05:25 +02:00
|
|
|
scheme: int = AliasGeneratorEnum.word.value,
|
|
|
|
in_hex: bool = False,
|
2023-04-20 12:14:53 +02:00
|
|
|
alias_domain: str = config.FIRST_ALIAS_DOMAIN,
|
|
|
|
retries: int = 10,
|
2019-12-28 01:03:59 +01:00
|
|
|
) -> str:
|
2019-12-26 12:21:28 +01:00
|
|
|
"""generate an email address that does not exist before
|
2020-06-25 13:05:25 +02:00
|
|
|
:param alias_domain: the domain used to generate the alias.
|
2019-12-26 12:21:28 +01:00
|
|
|
:param scheme: int, value of AliasGeneratorEnum, indicate how the email is generated
|
2023-04-20 12:14:53 +02:00
|
|
|
:param retries: int, How many times we can try to generate an alias in case of collision
|
2019-12-26 12:21:28 +01:00
|
|
|
:type in_hex: bool, if the generate scheme is uuid, is hex favorable?
|
|
|
|
"""
|
2023-04-20 12:14:53 +02:00
|
|
|
if retries <= 0:
|
|
|
|
raise Exception("Cannot generate alias after many retries")
|
2019-12-26 12:21:28 +01:00
|
|
|
if scheme == AliasGeneratorEnum.uuid.value:
|
|
|
|
name = uuid.uuid4().hex if in_hex else uuid.uuid4().__str__()
|
2020-06-25 13:05:25 +02:00
|
|
|
random_email = name + "@" + alias_domain
|
2019-12-26 12:21:28 +01:00
|
|
|
else:
|
2023-03-13 19:55:16 +01:00
|
|
|
random_email = random_words(2, 3) + "@" + alias_domain
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-05-20 18:12:14 +02:00
|
|
|
random_email = random_email.lower().strip()
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
# check that the client does not exist yet
|
2023-04-20 12:14:53 +02:00
|
|
|
if available_sl_email(random_email):
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.d("generate email %s", random_email)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
return random_email
|
|
|
|
|
|
|
|
# Rerun the function
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("email %s already exists, generate a new email", random_email)
|
2023-04-20 12:14:53 +02:00
|
|
|
return generate_random_alias_email(
|
|
|
|
scheme=scheme, in_hex=in_hex, retries=retries - 1
|
|
|
|
)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Alias(Base, ModelMixin):
|
|
|
|
__tablename__ = "alias"
|
2024-03-13 14:30:17 +01:00
|
|
|
|
|
|
|
FLAG_PARTNER_CREATED = 1 << 0
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
email = sa.Column(sa.String(128), unique=True, nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2020-04-26 10:37:40 +02:00
|
|
|
# the name to use when user replies/sends from alias
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(128), nullable=True, default=None)
|
2020-04-26 10:37:40 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
enabled = sa.Column(sa.Boolean(), default=True, nullable=False)
|
2024-03-13 14:30:17 +01:00
|
|
|
flags = sa.Column(
|
|
|
|
sa.BigInteger(), default=0, server_default="0", nullable=False, index=True
|
|
|
|
)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
custom_domain_id = sa.Column(
|
2022-02-26 17:51:50 +01:00
|
|
|
sa.ForeignKey("custom_domain.id", ondelete="cascade"), nullable=True, index=True
|
2019-12-02 01:28:50 +01:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
custom_domain = orm.relationship("CustomDomain", foreign_keys=[custom_domain_id])
|
2020-05-03 16:05:34 +02:00
|
|
|
|
2019-12-30 18:48:07 +01:00
|
|
|
# To know whether an alias is created "on the fly", i.e. via the custom domain catch-all feature
|
2021-10-12 14:36:47 +02:00
|
|
|
automatic_creation = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2019-12-30 18:48:07 +01:00
|
|
|
)
|
|
|
|
|
2020-01-08 21:23:41 +01:00
|
|
|
# to know whether an alias belongs to a directory
|
2021-10-12 14:36:47 +02:00
|
|
|
directory_id = sa.Column(
|
2022-02-26 17:51:50 +01:00
|
|
|
sa.ForeignKey("directory.id", ondelete="cascade"), nullable=True, index=True
|
2020-01-08 21:23:41 +01:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
note = sa.Column(sa.Text, default=None, nullable=True)
|
2020-02-05 09:45:29 +01:00
|
|
|
|
2020-02-10 17:11:09 +01:00
|
|
|
# an alias can be owned by another mailbox
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey("mailbox.id", ondelete="cascade"), nullable=False, index=True
|
2020-02-10 17:11:09 +01:00
|
|
|
)
|
|
|
|
|
2020-05-03 15:54:19 +02:00
|
|
|
# prefix _ to avoid this object being used accidentally.
|
|
|
|
# To have the list of all mailboxes, should use AliasInfo instead
|
2021-10-12 14:36:47 +02:00
|
|
|
_mailboxes = orm.relationship("Mailbox", secondary="alias_mailbox", lazy="joined")
|
2020-05-03 15:54:19 +02:00
|
|
|
|
2020-05-16 12:54:48 +02:00
|
|
|
# If the mailbox has PGP-enabled, user can choose disable the PGP on the alias
|
|
|
|
# this is useful when some senders already support PGP
|
2021-10-12 14:36:47 +02:00
|
|
|
disable_pgp = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-05-16 12:54:48 +02:00
|
|
|
)
|
|
|
|
|
2020-05-27 14:11:32 +02:00
|
|
|
# a way to bypass the bounce automatic disable mechanism
|
2021-10-12 14:36:47 +02:00
|
|
|
cannot_be_disabled = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-05-27 14:11:32 +02:00
|
|
|
)
|
|
|
|
|
2020-08-26 14:39:03 +02:00
|
|
|
# when a mailbox wants to send an email on behalf of the alias via the reverse-alias
|
|
|
|
# several checks are performed to avoid email spoofing
|
|
|
|
# this option allow disabling these checks
|
2021-10-12 14:36:47 +02:00
|
|
|
disable_email_spoofing_check = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-08-26 14:39:03 +02:00
|
|
|
)
|
|
|
|
|
2020-09-10 20:05:25 +02:00
|
|
|
# to know whether an alias is added using a batch import
|
2021-10-12 14:36:47 +02:00
|
|
|
batch_import_id = sa.Column(
|
|
|
|
sa.ForeignKey("batch_import.id", ondelete="SET NULL"),
|
2020-09-10 20:05:25 +02:00
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
)
|
|
|
|
|
2021-02-17 12:49:47 +01:00
|
|
|
# set in case of alias transfer.
|
2021-10-12 14:36:47 +02:00
|
|
|
original_owner_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="SET NULL"), nullable=True
|
2021-02-17 12:49:47 +01:00
|
|
|
)
|
|
|
|
|
2020-11-15 18:38:07 +01:00
|
|
|
# alias is pinned on top
|
2021-10-12 14:36:47 +02:00
|
|
|
pinned = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
2020-11-15 18:38:07 +01:00
|
|
|
|
2021-03-06 18:06:29 +01:00
|
|
|
# used to transfer an alias to another user
|
2021-10-12 14:36:47 +02:00
|
|
|
transfer_token = sa.Column(sa.String(64), default=None, unique=True, nullable=True)
|
2022-06-13 12:41:47 +02:00
|
|
|
transfer_token_expiration = sa.Column(
|
|
|
|
ArrowType, default=arrow.utcnow, nullable=True
|
|
|
|
)
|
2021-03-06 18:06:29 +01:00
|
|
|
|
2021-05-13 22:44:16 +02:00
|
|
|
# have I been pwned
|
2023-07-29 10:03:31 +02:00
|
|
|
hibp_last_check = sa.Column(ArrowType, default=None, index=True)
|
2021-10-12 14:36:47 +02:00
|
|
|
hibp_breaches = orm.relationship("Hibp", secondary="alias_hibp")
|
2021-05-13 22:44:16 +02:00
|
|
|
|
2021-08-04 09:29:56 +02:00
|
|
|
# to use Postgres full text search. Only applied on "note" column for now
|
|
|
|
# this is a generated Postgres column
|
2021-10-12 14:36:47 +02:00
|
|
|
ts_vector = sa.Column(
|
|
|
|
TSVector(), sa.Computed("to_tsvector('english', note)", persisted=True)
|
2021-08-04 09:29:56 +02:00
|
|
|
)
|
|
|
|
|
2024-02-15 15:48:02 +01:00
|
|
|
last_email_log_id = sa.Column(sa.Integer, default=None, nullable=True)
|
|
|
|
|
2021-08-04 09:29:56 +02:00
|
|
|
__table_args__ = (
|
|
|
|
Index("ix_video___ts_vector__", ts_vector, postgresql_using="gin"),
|
2021-08-20 12:14:20 +02:00
|
|
|
# index on note column using pg_trgm
|
2021-08-20 12:21:27 +02:00
|
|
|
Index(
|
|
|
|
"note_pg_trgm_index",
|
|
|
|
"note",
|
|
|
|
postgresql_ops={"note": "gin_trgm_ops"},
|
|
|
|
postgresql_using="gin",
|
|
|
|
),
|
2021-08-04 09:29:56 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id])
|
|
|
|
mailbox = orm.relationship("Mailbox", lazy="joined")
|
2019-11-08 09:11:01 +01:00
|
|
|
|
2020-05-10 16:57:47 +02:00
|
|
|
@property
|
|
|
|
def mailboxes(self):
|
|
|
|
ret = [self.mailbox]
|
|
|
|
for m in self._mailboxes:
|
2024-01-16 14:50:39 +01:00
|
|
|
if m.id is not self.mailbox.id:
|
|
|
|
ret.append(m)
|
2020-05-10 16:57:47 +02:00
|
|
|
|
2020-06-28 11:15:29 +02:00
|
|
|
ret = [mb for mb in ret if mb.verified]
|
2020-06-10 22:32:00 +02:00
|
|
|
ret = sorted(ret, key=lambda mb: mb.email)
|
|
|
|
|
2020-05-10 16:57:47 +02:00
|
|
|
return ret
|
|
|
|
|
2022-01-08 00:09:45 +01:00
|
|
|
def authorized_addresses(self) -> [str]:
|
|
|
|
"""return addresses that can send on behalf of this alias, i.e. can send emails to this alias's reverse-aliases
|
|
|
|
Including its mailboxes and their authorized addresses
|
|
|
|
"""
|
|
|
|
mailboxes = self.mailboxes
|
|
|
|
ret = [mb.email for mb in mailboxes]
|
|
|
|
for mailbox in mailboxes:
|
|
|
|
for aa in mailbox.authorized_addresses:
|
|
|
|
ret.append(aa.email)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
2020-05-16 12:54:48 +02:00
|
|
|
def mailbox_support_pgp(self) -> bool:
|
|
|
|
"""return True of one of the mailboxes support PGP"""
|
|
|
|
for mb in self.mailboxes:
|
2020-11-24 11:18:16 +01:00
|
|
|
if mb.pgp_enabled():
|
2020-05-16 12:54:48 +02:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2020-05-16 18:19:47 +02:00
|
|
|
def pgp_enabled(self) -> bool:
|
|
|
|
if self.mailbox_support_pgp() and not self.disable_pgp:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2022-01-06 15:29:37 +01:00
|
|
|
@staticmethod
|
|
|
|
def get_custom_domain(alias_address) -> Optional["CustomDomain"]:
|
|
|
|
alias_domain = validate_email(
|
|
|
|
alias_address, check_deliverability=False, allow_smtputf8=False
|
|
|
|
).domain
|
|
|
|
|
|
|
|
# handle the case a SLDomain is also a CustomDomain
|
|
|
|
if SLDomain.get_by(domain=alias_domain) is None:
|
|
|
|
custom_domain = CustomDomain.get_by(domain=alias_domain)
|
|
|
|
if custom_domain:
|
|
|
|
return custom_domain
|
|
|
|
|
2020-05-07 22:23:36 +02:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
2020-09-28 17:40:30 +02:00
|
|
|
commit = kw.pop("commit", False)
|
2022-01-07 10:04:12 +01:00
|
|
|
flush = kw.pop("flush", False)
|
2020-09-28 17:40:30 +02:00
|
|
|
|
2022-01-07 10:04:12 +01:00
|
|
|
new_alias = cls(**kw)
|
2024-01-30 18:29:59 +01:00
|
|
|
user = User.get(new_alias.user_id)
|
|
|
|
if user.is_premium():
|
2024-02-01 14:47:15 +01:00
|
|
|
limits = config.ALIAS_CREATE_RATE_LIMIT_PAID
|
2024-01-30 18:29:59 +01:00
|
|
|
else:
|
2024-02-01 14:47:15 +01:00
|
|
|
limits = config.ALIAS_CREATE_RATE_LIMIT_FREE
|
2024-01-30 18:29:59 +01:00
|
|
|
# limits is array of (hits,days)
|
|
|
|
for limit in limits:
|
|
|
|
key = f"alias_create_{limit[1]}d:{user.id}"
|
2024-02-01 14:47:15 +01:00
|
|
|
rate_limiter.check_bucket_limit(key, limit[0], limit[1])
|
2020-05-07 22:23:36 +02:00
|
|
|
|
|
|
|
email = kw["email"]
|
2020-09-02 09:56:16 +02:00
|
|
|
# make sure email is lowercase and doesn't have any whitespace
|
2021-01-11 12:29:40 +01:00
|
|
|
email = sanitize_email(email)
|
2020-09-02 09:56:16 +02:00
|
|
|
|
|
|
|
# make sure alias is not in global trash, i.e. DeletedAlias table
|
2020-05-07 22:23:36 +02:00
|
|
|
if DeletedAlias.get_by(email=email):
|
|
|
|
raise AliasInTrashError
|
|
|
|
|
2020-05-23 19:48:45 +02:00
|
|
|
if DomainDeletedAlias.get_by(email=email):
|
2020-05-23 19:35:18 +02:00
|
|
|
raise AliasInTrashError
|
|
|
|
|
2022-01-06 15:29:37 +01:00
|
|
|
# detect whether alias should belong to a custom domain
|
|
|
|
if "custom_domain_id" not in kw:
|
|
|
|
custom_domain = Alias.get_custom_domain(email)
|
|
|
|
if custom_domain:
|
2022-01-07 10:04:12 +01:00
|
|
|
new_alias.custom_domain_id = custom_domain.id
|
|
|
|
|
|
|
|
Session.add(new_alias)
|
2022-10-14 17:35:34 +02:00
|
|
|
DailyMetric.get_or_create_today_metric().nb_alias += 1
|
2022-01-06 15:29:37 +01:00
|
|
|
|
2024-06-28 15:34:16 +02:00
|
|
|
if (
|
|
|
|
new_alias.flags & cls.FLAG_PARTNER_CREATED > 0
|
|
|
|
and new_alias.user.flags & User.FLAG_CREATED_ALIAS_FROM_PARTNER == 0
|
|
|
|
):
|
|
|
|
user.flags = user.flags | User.FLAG_CREATED_ALIAS_FROM_PARTNER
|
|
|
|
|
2020-09-28 17:40:30 +02:00
|
|
|
if commit:
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2022-01-07 10:04:12 +01:00
|
|
|
|
|
|
|
if flush:
|
|
|
|
Session.flush()
|
|
|
|
|
2024-09-06 15:47:47 +02:00
|
|
|
# Internal import to avoid global import cycles
|
2024-10-14 12:45:00 +02:00
|
|
|
from app.alias_audit_log_utils import AliasAuditLogAction, emit_alias_audit_log
|
2024-09-06 15:47:47 +02:00
|
|
|
from app.events.event_dispatcher import EventDispatcher
|
|
|
|
from app.events.generated.event_pb2 import AliasCreated, EventContent
|
|
|
|
|
|
|
|
event = AliasCreated(
|
2024-09-13 14:25:38 +02:00
|
|
|
id=new_alias.id,
|
|
|
|
email=new_alias.email,
|
|
|
|
note=new_alias.note,
|
2024-09-06 15:47:47 +02:00
|
|
|
enabled=True,
|
2024-09-13 13:39:41 +02:00
|
|
|
created_at=int(new_alias.created_at.timestamp),
|
2024-09-06 15:47:47 +02:00
|
|
|
)
|
|
|
|
EventDispatcher.send_event(user, EventContent(alias_created=event))
|
2024-10-14 12:45:00 +02:00
|
|
|
emit_alias_audit_log(
|
|
|
|
new_alias, AliasAuditLogAction.CreateAlias, "New alias created"
|
|
|
|
)
|
2024-09-06 15:47:47 +02:00
|
|
|
|
2022-01-07 10:04:12 +01:00
|
|
|
return new_alias
|
2020-05-07 22:23:36 +02:00
|
|
|
|
2019-12-08 16:59:06 +01:00
|
|
|
@classmethod
|
2020-03-05 20:32:08 +01:00
|
|
|
def create_new(cls, user, prefix, note=None, mailbox_id=None):
|
2020-09-02 09:56:16 +02:00
|
|
|
prefix = prefix.lower().strip().replace(" ", "")
|
|
|
|
|
2019-12-08 16:59:06 +01:00
|
|
|
if not prefix:
|
|
|
|
raise Exception("alias prefix cannot be empty")
|
|
|
|
|
2019-12-09 22:36:04 +01:00
|
|
|
# find the right suffix - avoid infinite loop by running this at max 1000 times
|
2022-02-06 21:37:43 +01:00
|
|
|
for _ in range(1000):
|
2021-06-27 17:51:13 +02:00
|
|
|
suffix = user.get_random_alias_suffix()
|
2022-06-30 11:40:01 +02:00
|
|
|
email = f"{prefix}.{suffix}@{config.FIRST_ALIAS_DOMAIN}"
|
2019-12-08 16:59:06 +01:00
|
|
|
|
2023-04-20 12:14:53 +02:00
|
|
|
if available_sl_email(email):
|
2019-12-09 22:36:04 +01:00
|
|
|
break
|
2019-12-08 16:59:06 +01:00
|
|
|
|
2020-03-17 11:51:40 +01:00
|
|
|
return Alias.create(
|
2020-03-05 20:32:08 +01:00
|
|
|
user_id=user.id,
|
|
|
|
email=email,
|
|
|
|
note=note,
|
|
|
|
mailbox_id=mailbox_id or user.default_mailbox_id,
|
2020-02-23 07:58:09 +01:00
|
|
|
)
|
2019-12-08 16:59:06 +01:00
|
|
|
|
2020-08-14 12:02:33 +02:00
|
|
|
@classmethod
|
|
|
|
def delete(cls, obj_id):
|
|
|
|
raise Exception("should use delete_alias(alias,user) instead")
|
|
|
|
|
2019-12-23 16:34:02 +01:00
|
|
|
@classmethod
|
2019-12-28 01:03:59 +01:00
|
|
|
def create_new_random(
|
2020-03-11 12:24:30 +01:00
|
|
|
cls,
|
|
|
|
user,
|
|
|
|
scheme: int = AliasGeneratorEnum.word.value,
|
|
|
|
in_hex: bool = False,
|
|
|
|
note: str = None,
|
2019-12-28 01:03:59 +01:00
|
|
|
):
|
2019-12-23 16:34:02 +01:00
|
|
|
"""create a new random alias"""
|
2020-07-04 23:27:02 +02:00
|
|
|
custom_domain = None
|
2020-06-25 13:05:25 +02:00
|
|
|
|
2020-10-15 16:21:31 +02:00
|
|
|
random_email = None
|
|
|
|
|
2020-12-31 14:06:32 +01:00
|
|
|
if user.default_alias_custom_domain_id:
|
|
|
|
custom_domain = CustomDomain.get(user.default_alias_custom_domain_id)
|
2023-04-20 12:14:53 +02:00
|
|
|
random_email = generate_random_alias_email(
|
2020-07-04 23:27:02 +02:00
|
|
|
scheme=scheme, in_hex=in_hex, alias_domain=custom_domain.domain
|
|
|
|
)
|
2020-12-31 14:14:56 +01:00
|
|
|
elif user.default_alias_public_domain_id:
|
|
|
|
sl_domain: SLDomain = SLDomain.get(user.default_alias_public_domain_id)
|
2020-10-15 16:52:38 +02:00
|
|
|
if sl_domain.premium_only and not user.is_premium():
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("%s not premium, cannot use %s", user, sl_domain)
|
2020-10-15 16:21:31 +02:00
|
|
|
else:
|
2023-04-20 12:14:53 +02:00
|
|
|
random_email = generate_random_alias_email(
|
2020-10-15 16:52:38 +02:00
|
|
|
scheme=scheme, in_hex=in_hex, alias_domain=sl_domain.domain
|
2020-10-15 16:21:31 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
if not random_email:
|
2023-04-20 12:14:53 +02:00
|
|
|
random_email = generate_random_alias_email(scheme=scheme, in_hex=in_hex)
|
2020-06-25 13:05:25 +02:00
|
|
|
|
|
|
|
alias = Alias.create(
|
2020-03-11 12:24:30 +01:00
|
|
|
user_id=user.id,
|
|
|
|
email=random_email,
|
|
|
|
mailbox_id=user.default_mailbox_id,
|
|
|
|
note=note,
|
2020-03-05 17:03:07 +01:00
|
|
|
)
|
2019-12-23 16:34:02 +01:00
|
|
|
|
2020-07-04 23:27:02 +02:00
|
|
|
if custom_domain:
|
|
|
|
alias.custom_domain_id = custom_domain.id
|
2020-06-25 13:05:25 +02:00
|
|
|
|
|
|
|
return alias
|
|
|
|
|
2020-02-22 15:09:07 +01:00
|
|
|
def mailbox_email(self):
|
|
|
|
if self.mailbox_id:
|
|
|
|
return self.mailbox.email
|
|
|
|
else:
|
|
|
|
return self.user.email
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
def __repr__(self):
|
2020-03-17 11:51:40 +01:00
|
|
|
return f"<Alias {self.id} {self.email}>"
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class ClientUser(Base, ModelMixin):
|
|
|
|
__tablename__ = "client_user"
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("user_id", "client_id", name="uq_client_user"),
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
# Null means client has access to user original email
|
2023-04-14 19:08:52 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=True, index=True
|
|
|
|
)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-07-22 19:55:24 +02:00
|
|
|
# user can decide to send to client another name
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(
|
|
|
|
sa.String(128), nullable=True, default=None, server_default=text("NULL")
|
2021-04-01 12:31:37 +02:00
|
|
|
)
|
|
|
|
|
2019-07-22 19:55:24 +02:00
|
|
|
# user can decide to send to client a default avatar
|
2021-10-12 14:36:47 +02:00
|
|
|
default_avatar = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2019-07-22 19:55:24 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias = orm.relationship(Alias, backref="client_users")
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
|
|
|
client = orm.relationship(Client)
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
def get_email(self):
|
2020-03-17 12:01:18 +01:00
|
|
|
return self.alias.email if self.alias_id else self.user.email
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-08-16 12:56:13 +02:00
|
|
|
def get_user_name(self):
|
|
|
|
if self.name:
|
|
|
|
return self.name
|
|
|
|
else:
|
|
|
|
return self.user.name
|
|
|
|
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
def get_user_info(self) -> dict:
|
|
|
|
"""return user info according to client scope
|
2019-07-03 11:47:42 +02:00
|
|
|
Return dict with key being scope name. For now all the fields are the same for all clients:
|
|
|
|
|
|
|
|
{
|
|
|
|
"client": "Demo",
|
|
|
|
"email": "test-avk5l@mail-tester.com",
|
|
|
|
"email_verified": true,
|
|
|
|
"id": 1,
|
|
|
|
"name": "Son GM",
|
|
|
|
"avatar_url": "http://s3..."
|
|
|
|
}
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
"""
|
2019-08-11 00:32:00 +02:00
|
|
|
res = {
|
|
|
|
"id": self.id,
|
|
|
|
"client": self.client.name,
|
|
|
|
"email_verified": True,
|
|
|
|
"sub": str(self.id),
|
|
|
|
}
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
2019-07-03 11:47:42 +02:00
|
|
|
for scope in self.client.get_scopes():
|
2019-07-03 12:13:28 +02:00
|
|
|
if scope == Scope.NAME:
|
2019-07-22 21:28:17 +02:00
|
|
|
if self.name:
|
2021-01-11 10:22:39 +01:00
|
|
|
res[Scope.NAME.value] = self.name or ""
|
2019-07-22 21:28:17 +02:00
|
|
|
else:
|
2021-01-11 10:22:39 +01:00
|
|
|
res[Scope.NAME.value] = self.user.name or ""
|
2019-07-03 12:13:28 +02:00
|
|
|
elif scope == Scope.AVATAR_URL:
|
2019-07-03 11:47:42 +02:00
|
|
|
if self.user.profile_picture_id:
|
2019-07-22 22:24:57 +02:00
|
|
|
if self.default_avatar:
|
2022-06-30 11:40:01 +02:00
|
|
|
res[Scope.AVATAR_URL.value] = (
|
|
|
|
config.URL + "/static/default-avatar.png"
|
|
|
|
)
|
2019-07-22 22:24:57 +02:00
|
|
|
else:
|
2019-08-22 18:14:32 +02:00
|
|
|
res[Scope.AVATAR_URL.value] = self.user.profile_picture.get_url(
|
2022-06-30 11:40:01 +02:00
|
|
|
config.AVATAR_URL_EXPIRATION
|
2019-08-22 18:14:32 +02:00
|
|
|
)
|
2019-07-03 11:47:42 +02:00
|
|
|
else:
|
2019-07-03 12:13:28 +02:00
|
|
|
res[Scope.AVATAR_URL.value] = None
|
|
|
|
elif scope == Scope.EMAIL:
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
# Use generated email
|
2020-03-17 12:01:18 +01:00
|
|
|
if self.alias_id:
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.d(
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
"Use gen email for user %s, client %s", self.user, self.client
|
|
|
|
)
|
2020-03-17 11:51:40 +01:00
|
|
|
res[Scope.EMAIL.value] = self.alias.email
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
# Use user original email
|
|
|
|
else:
|
2019-07-03 12:13:28 +02:00
|
|
|
res[Scope.EMAIL.value] = self.user.email
|
create BaseForm to enable CSRF
register page
redirect user to dashboard if they are logged in
enable csrf for login page
Set models more strict
bootstrap developer page
add helper method to ModelMixin, remove CRUDMixin
display list of clients on developer index, add copy client-secret to clipboard using clipboardjs
add toastr and use jquery non slim
display a toast when user copies the client-secret
create new client, generate client-id using unidecode
client detail page: can edit client
add delete client
implement /oauth/authorize and /oauth/allow-deny
implement /oauth/token
add /oauth/user_info endpoint
handle scopes: wip
take into account scope: display scope, return user data according to scope
create virtual-domain, gen email, client_user model WIP
create authorize_nonlogin_user page
user can choose to generate a new email
no need to interfere with root logger
log for before and after request
if user has already allowed a client: generate a auth-code and redirect user to client
get_user_info takes into account gen email
display list of clients that have user has authorised
use yk-client domain instead of localhost as cookie depends on the domain name
use wtforms instead of flask_wtf
Dockerfile
delete virtual domain
EMAIL_DOMAIN can come from env var
bind to host 0.0.0.0
fix signup error: use session as default csrf_context
rename yourkey to simplelogin
add python-dotenv, ipython, sqlalchemy_utils
create DB_URI, FLASK_SECRET. Load config from CONFIG file if exist
add shortcuts to logging
create shell
add psycopg2
do not add local data in Dockerfile
add drop_db into shell
add shell.prepare_db()
fix prepare_db
setup sentry
copy assets from tabler/dist
add icon downloaded from https://commons.wikimedia.org/wiki/File:Simpleicons_Interface_key-tool-1.svg
integrate tabler - login and register page
add favicon
template: default, header. Use gravatar for user avatar url
use default template for dashboard, developer page
use another icon
add clipboard and notie
prettify dashboard
add notie css
add fake gen email and client-user
prettify list client page, use notie for toast
add email, name scope to new client
display client scope in client list
prettify new-client, client-detail
add sentry-sdk and blinker
add arrow, add dt jinja filter, prettify logout, dashboard
comment "last used" in dashboard for now
prettify date display
add copy email to clipboard to dashboard
use "users" as table name for User as "user" is reserved key in postgres
call prepare_db() when creating new db
error page 400, 401, 403, 404
prettify authorize_login_user
create already_authorize.html for user who has already authorized a client
user can generate new email
display all other generated emails
add ENV variable, only reset DB when ENV=local
fix: not return other users gen emails
display nb users for each client
refactor shell: remove prepare_db()
add sendgrid
add /favicon.ico route
add new config: URL, SUPPORT_EMAIL, SENDGRID_API_KEY
user needs to activate their account before login
create copy button on dashboard
client can have multiple redirect uris, in client detail can add/remove redirect-uri,
use redirect_uri passed in /authorize
refactor: move get_user_info into ClientUser model
dashboard: display all apps, all generated emails
add "id" into user_info
add trigger email button
invalidate the session at each new version by changing the secret
centralize Client creation into Client.create_new
user can enable/disable email forwarding
setup auto dismiss alert: just add .alert-auto-dismiss
move name down in register form
add shell.add_real_data
move blueprint template to its own package
prettify authorize page for non-authenticated user
update readme, return error if not redirect_uri
add flask-wtf, use psycopg2-binary
use flask-wtf FlaskForm instead of Form
rename email -> email_utils
add AWS_REGION, BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY to config
add s3 module
add File model, add Client.icon_id
handle client icon update
can create client with icon
display client icon in client list page
add Client.home_url
take into account Client.home_url
add boto3
register: ask name first
only show "trigger test email" if email forwarding is enabled
display gen email in alphabetical order, client in client.name alphabetical order
better error page
the modal does not get close when user clicks outside of modal
add Client.published column
discover page that displays all published Client
add missing bootstrap.bundle.min.js.map
developer can publish/unpublish their app in discover
use notie for display flash message
create hotmail account
fix missing jquery
add footer, add global jinja2 variable
strengthen model: use nullable=False whenever possible,
rename client_id to oauth_client_id, client_secret to oauth_client_secret
add flask-migrate
init migrate
1st migrate version
fix rename client_id -> oauth_client_id
prettify UI
use flask_migrate.upgrade() instead of db.create_all()
make sure requirejs.config is called for all page
enable sentry for js, use uppercase for global jinja2 variables
add flask-admin
add User.is_admin column
setup flask admin, only accessible to admin user
fix migration: add server_default
replace session[redirect_after_login] by "next" request args
add pyproject.toml: ignore migrations/ in black
add register waiting_activation_email page
better email wording
add pytest
add get_host_name_and_scheme and tests
example fail test
fix test
fix client-id display
add flask-cors
/user_info supports cors, add /me as /user_info synonym
return client in /me
support implicit flow
no need to use with "app.app_context()"
add watchtower to requirement
add param ENABLE_CLOUDWATCH, CLOUDWATCH_LOG_GROUP, CLOUDWATCH_LOG_STREAM
add cloudwatch logger if cloudwatch is enabled
add 500 error page
add help text for list of used client
display list of app/website that an email has been used
click on client name brings to client detail page
create style.css to add additional style, append its url with the current sha1 to avoid cache
POC on how to send email using postfix
add sqlalchemy-utils
use arrow instead of datetime
add new params STRIPE_API, STRIPE_YEARLY_SKU, STRIPE_MONTHLY_PLAN
show full error in local
add plan, plan_expiration to User, need to create enum directly in migration script, cf https://github.com/sqlalchemy/alembic/issues/67
reformat all html files: use space instead of tab
new user will have trial plan for 15 days
add new param MAX_NB_EMAIL_FREE_PLAN
only user with enough quota can create new email
if user cannot create new gen email, pick randomly one from existing gen emails. Use flush instead of commit
rename STRIPE_YEARLY_SKU -> STRIPE_YEARLY_PLAN
open client page in discover in a new tab
add stripe
not logging /static call: disable flask logging, replace by after_request
add param STRIPE_SECRET_KEY
add 3 columns stripe_customer_id, stripe_card_token, stripe_subscription_id
user can upgrade their pricing
add setting page as coming-soon
add GenEmail, ClientUser to admin
ignore /admin/static logging
add more fake data
add ondelete="cascade" whenever possible
rename plan_expiration -> trial_expiration
reset migration: delete old migrations, create new one
rename test_send_email -> poc_send_email to avoid the file being called by pytest
add new param LYRA_ANALYTICS_ID, add lyra analytics
add how to create new migration into readme
add drift to base.html
notify admin when new user signs up or pays subscription
log exception in case of 500
use sendgrid to notify admin
add alias /userinfo to user_info endpoint
add change_password to shell
add info on how payment is handled
invite user to retry if card not working
remove drift and add "contact us" link
move poc_send_email into poc/
support getting client-id, client-secret from form-data in addition to basic auth
client-id, client-secret is passed in form-data by passport-oauth2 for ex
add jwtRS256 private and public key
add jwk-jws-jwt poc
add new param OPENID_PRIVATE_KEY_PATH, OPENID_PRIVATE_KEY_PATH
add scope, redirect_url to AuthorizationCode and OauthToken
take into scope when creating oauth-token, authorization-code
add jwcrypto
add jose_utils: make_id_token and verify_id_token
add &scope to redirect uri
add "email_verified": True into user_info
fix user not activated
add /oauth2 as alias for /oauth
handle case where scope and state are empty
remove threaded=False
Use Email Alias as wording
remove help text
user can re-send activation email
add "expired" into ActivationCode
Handle the case activation code is expired
reformat: use form.validate_on_submit instead of request.method == post && form.validate
use error text instead of flash()
display client oauth-id and oauth-secret on client detail page
not display oauth-secret on client listing
fix expiration check
improve page title, footer
add /jwks and /.well-known/openid-configuration
init properly tests, fix blueprint conflict bug in flask-admin
create oauth_models module
rename Scope -> ScopeE to distinguish with Scope DB model
set app.url_map.strict_slashes = False
use ScopeE instead of SCOPE_NAME, ...
support access_token passed as args in /userinfo
merge /allow-deny into /authorize
improve wording
take into account the case response_type=code and openid is in scope
take into account response_type=id_token, id_token token, id_token code
make sure to use in-memory db in test
fix scope can be null
allow cross_origin for /.well-known/openid-configuration and /jwks
fix footer link
center authorize form
rename trial_expiration to plan_expiration
move stripe init to create_app()
use real email to be able to receive email notification
add user.profile_picture_id column
use user profile picture and fallback to gravatar
use nguyenkims+local@gm to distinguish with staging
handle plan cancel, reactivation, user profile update
fix can_create_new_email
create cron.py that set plan to free when expired
add crontab.yml
add yacron
use notify_admin instead of LOG.error
add ResetPasswordCode model
user can change password in setting
increase display time for notie
add forgot_password page
If login error: redirect to this page upon success login.
hide discover tab
add column user.is_developer
only show developer menu to developer
comment out the publish button
set local user to developer
make sure only developer can access /developer blueprint
User is invited to upgrade if they are in free plan or their trial ends soon
not sending email when in local mode
create Partner model
create become partner page
use normal error handling on local
fix migration
add "import sqlalchemy_utils" into migration template
small refactoring on setting page
handle promo code. TODO: add migration file
add migration for user.promo_codes
move email alias on top of apps in dashboard
add introjs
move encode_url to utils
create GenEmail.create_new_gen_email
create a first alias mail to show user how to use when they login
show intro when user visits the website the first time
fix register
2019-07-02 09:20:12 +02:00
|
|
|
|
|
|
|
return res
|
2019-11-07 17:34:18 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Contact(Base, ModelMixin):
|
2019-11-07 17:34:18 +01:00
|
|
|
"""
|
2020-03-14 12:22:43 +01:00
|
|
|
Store configuration of sender (website-email) and alias.
|
2019-11-07 17:34:18 +01:00
|
|
|
"""
|
2019-11-08 09:11:01 +01:00
|
|
|
|
2023-02-10 10:07:43 +01:00
|
|
|
MAX_NAME_LENGTH = 512
|
|
|
|
|
2024-09-19 16:20:56 +02:00
|
|
|
FLAG_PARTNER_CREATED = 1 << 0
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "contact"
|
|
|
|
|
2019-11-07 17:34:18 +01:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("alias_id", "website_email", name="uq_contact"),
|
2019-11-07 17:34:18 +01:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2019-11-07 17:34:18 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(
|
|
|
|
sa.String(512), nullable=True, default=None, server_default=text("NULL")
|
2020-04-05 12:48:59 +02:00
|
|
|
)
|
2020-04-05 12:18:18 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
website_email = sa.Column(sa.String(512), nullable=False)
|
2019-11-07 17:34:18 +01:00
|
|
|
|
2019-12-09 22:40:31 +01:00
|
|
|
# the email from header, e.g. AB CD <ab@cd.com>
|
|
|
|
# nullable as this field is added after website_email
|
2021-10-12 14:36:47 +02:00
|
|
|
website_from = sa.Column(sa.String(1024), nullable=True)
|
2019-12-09 22:40:31 +01:00
|
|
|
|
2019-11-07 17:34:18 +01:00
|
|
|
# when user clicks on "reply", they will reply to this address.
|
|
|
|
# This address allows to hide user personal email
|
|
|
|
# this reply email is created every time a website sends an email to user
|
2021-10-25 14:33:42 +02:00
|
|
|
# it used to have the prefix "reply+" or "ra+"
|
2021-10-12 14:36:47 +02:00
|
|
|
reply_email = sa.Column(sa.String(512), nullable=False, index=True)
|
2019-11-08 07:55:29 +01:00
|
|
|
|
2020-03-28 19:05:27 +01:00
|
|
|
# whether a contact is created via CC
|
2021-10-12 14:36:47 +02:00
|
|
|
is_cc = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
2020-03-28 19:05:27 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
pgp_public_key = sa.Column(sa.Text, nullable=True)
|
2023-04-14 18:29:06 +02:00
|
|
|
pgp_finger_print = sa.Column(sa.String(512), nullable=True, index=True)
|
2020-06-07 00:04:59 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias = orm.relationship(Alias, backref="contacts")
|
|
|
|
user = orm.relationship(User)
|
2019-12-15 16:17:37 +01:00
|
|
|
|
2020-08-04 11:36:53 +02:00
|
|
|
# the latest reply sent to this contact
|
|
|
|
latest_reply: Optional[Arrow] = None
|
|
|
|
|
2020-09-14 17:55:55 +02:00
|
|
|
# to investigate why the website_email is sometimes not correctly parsed
|
|
|
|
# the envelope mail_from
|
2021-10-12 14:36:47 +02:00
|
|
|
mail_from = sa.Column(sa.Text, nullable=True, default=None)
|
2020-09-14 17:55:55 +02:00
|
|
|
|
2020-11-14 15:54:06 +01:00
|
|
|
# a contact can have an empty email address, in this case it can't receive emails
|
2021-10-12 14:36:47 +02:00
|
|
|
invalid_email = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-11-14 15:54:06 +01:00
|
|
|
)
|
|
|
|
|
2021-10-28 10:12:52 +02:00
|
|
|
# emails sent from this contact will be blocked
|
|
|
|
block_forward = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2022-01-07 10:21:31 +01:00
|
|
|
# whether contact is created automatically during the forward phase
|
|
|
|
automatic_created = sa.Column(sa.Boolean, nullable=True, default=False)
|
|
|
|
|
2024-09-19 16:20:56 +02:00
|
|
|
# contact flags
|
|
|
|
flags = sa.Column(sa.Integer, nullable=False, default=0, server_default="0")
|
|
|
|
|
2020-06-07 00:04:59 +02:00
|
|
|
@property
|
|
|
|
def email(self):
|
|
|
|
return self.website_email
|
|
|
|
|
2022-01-07 10:04:12 +01:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
commit = kw.pop("commit", False)
|
|
|
|
flush = kw.pop("flush", False)
|
|
|
|
|
2023-08-04 14:01:21 +02:00
|
|
|
new_contact = cls(**kw)
|
|
|
|
|
|
|
|
website_email = kw["website_email"]
|
2022-01-07 10:04:12 +01:00
|
|
|
# make sure email is lowercase and doesn't have any whitespace
|
2023-08-04 14:01:21 +02:00
|
|
|
website_email = sanitize_email(website_email)
|
2022-01-07 10:04:12 +01:00
|
|
|
|
2022-01-07 14:27:53 +01:00
|
|
|
# make sure contact.website_email isn't a reverse alias
|
2022-06-30 11:40:01 +02:00
|
|
|
if website_email != config.NOREPLY:
|
2022-05-20 17:59:41 +02:00
|
|
|
orig_contact = Contact.get_by(reply_email=website_email)
|
|
|
|
if orig_contact:
|
|
|
|
raise CannotCreateContactForReverseAlias(str(orig_contact))
|
2022-01-07 10:04:12 +01:00
|
|
|
|
|
|
|
Session.add(new_contact)
|
|
|
|
|
|
|
|
if commit:
|
|
|
|
Session.commit()
|
|
|
|
|
|
|
|
if flush:
|
|
|
|
Session.flush()
|
|
|
|
|
|
|
|
return new_contact
|
|
|
|
|
2019-12-15 16:17:37 +01:00
|
|
|
def website_send_to(self):
|
|
|
|
"""return the email address with name.
|
2020-04-05 12:48:59 +02:00
|
|
|
to use when user wants to send an email from the alias
|
|
|
|
Return
|
2021-10-25 14:33:42 +02:00
|
|
|
"First Last | email at example.com" <reverse-alias@SL>
|
2020-04-05 12:48:59 +02:00
|
|
|
"""
|
2020-02-10 17:11:09 +01:00
|
|
|
|
2020-04-05 12:48:59 +02:00
|
|
|
# Prefer using contact name if possible
|
2020-08-12 16:12:41 +02:00
|
|
|
user = self.user
|
2020-04-05 12:48:59 +02:00
|
|
|
name = self.name
|
2020-08-12 16:12:41 +02:00
|
|
|
email = self.website_email
|
|
|
|
|
|
|
|
if (
|
|
|
|
not user
|
|
|
|
or not SenderFormatEnum.has_value(user.sender_format)
|
|
|
|
or user.sender_format == SenderFormatEnum.AT.value
|
|
|
|
):
|
|
|
|
email = email.replace("@", " at ")
|
|
|
|
elif user.sender_format == SenderFormatEnum.A.value:
|
|
|
|
email = email.replace("@", "(a)")
|
2020-03-15 23:10:20 +01:00
|
|
|
|
2020-04-05 12:48:59 +02:00
|
|
|
# if no name, try to parse it from website_from
|
|
|
|
if not name and self.website_from:
|
|
|
|
try:
|
2021-09-10 17:06:38 +02:00
|
|
|
name = address.parse(self.website_from).display_name
|
2020-04-05 12:48:59 +02:00
|
|
|
except Exception:
|
|
|
|
# Skip if website_from is wrongly formatted
|
2021-09-10 17:06:38 +02:00
|
|
|
LOG.e(
|
2020-04-05 12:48:59 +02:00
|
|
|
"Cannot parse contact %s website_from %s", self, self.website_from
|
|
|
|
)
|
|
|
|
name = ""
|
|
|
|
|
|
|
|
# remove all double quote
|
|
|
|
if name:
|
|
|
|
name = name.replace('"', "")
|
|
|
|
|
|
|
|
if name:
|
2020-08-12 16:12:41 +02:00
|
|
|
name = name + " | " + email
|
2020-04-05 12:48:59 +02:00
|
|
|
else:
|
2020-08-12 16:12:41 +02:00
|
|
|
name = email
|
2020-03-15 23:02:06 +01:00
|
|
|
|
2020-03-15 23:10:20 +01:00
|
|
|
# cannot use formataddr here as this field is for email client, not for MTA
|
2020-04-05 12:48:59 +02:00
|
|
|
return f'"{name}" <{self.reply_email}>'
|
2019-12-15 16:17:37 +01:00
|
|
|
|
2020-04-05 15:21:04 +02:00
|
|
|
def new_addr(self):
|
|
|
|
"""
|
2020-05-15 16:14:12 +02:00
|
|
|
Replace original email by reply_email. Possible formats:
|
|
|
|
- First Last - first at example.com <reply_email> OR
|
|
|
|
- First Last - first(a)example.com <reply_email> OR
|
2021-12-28 10:49:37 +01:00
|
|
|
- First Last <reply_email>
|
|
|
|
- first at example.com <reply_email>
|
|
|
|
- reply_email
|
2020-04-05 15:21:04 +02:00
|
|
|
And return new address with RFC 2047 format
|
|
|
|
"""
|
|
|
|
user = self.user
|
2021-09-20 12:27:36 +02:00
|
|
|
sender_format = user.sender_format if user else SenderFormatEnum.AT.value
|
|
|
|
|
2021-12-28 10:49:37 +01:00
|
|
|
if sender_format == SenderFormatEnum.NO_NAME.value:
|
|
|
|
return self.reply_email
|
|
|
|
|
|
|
|
if sender_format == SenderFormatEnum.NAME_ONLY.value:
|
|
|
|
new_name = self.name
|
|
|
|
elif sender_format == SenderFormatEnum.AT_ONLY.value:
|
|
|
|
new_name = self.website_email.replace("@", " at ").strip()
|
|
|
|
elif sender_format == SenderFormatEnum.AT.value:
|
2021-09-20 12:27:36 +02:00
|
|
|
formatted_email = self.website_email.replace("@", " at ").strip()
|
2021-12-28 10:49:37 +01:00
|
|
|
new_name = (
|
|
|
|
(self.name + " - " + formatted_email)
|
|
|
|
if self.name and self.name != self.website_email.strip()
|
|
|
|
else formatted_email
|
|
|
|
)
|
|
|
|
else: # SenderFormatEnum.A.value
|
2021-09-20 12:27:36 +02:00
|
|
|
formatted_email = self.website_email.replace("@", "(a)").strip()
|
2021-12-28 10:49:37 +01:00
|
|
|
new_name = (
|
|
|
|
(self.name + " - " + formatted_email)
|
|
|
|
if self.name and self.name != self.website_email.strip()
|
|
|
|
else formatted_email
|
|
|
|
)
|
2020-04-05 15:21:04 +02:00
|
|
|
|
2022-09-05 08:40:24 +02:00
|
|
|
from app.email_utils import sl_formataddr
|
|
|
|
|
|
|
|
new_addr = sl_formataddr((new_name, self.reply_email)).strip()
|
2020-04-05 15:21:04 +02:00
|
|
|
return new_addr.strip()
|
|
|
|
|
2020-03-17 11:10:50 +01:00
|
|
|
def last_reply(self) -> "EmailLog":
|
2019-12-15 16:17:37 +01:00
|
|
|
"""return the most recent reply"""
|
|
|
|
return (
|
2021-10-12 14:36:47 +02:00
|
|
|
EmailLog.filter_by(contact_id=self.id, is_reply=True)
|
2020-03-17 11:10:50 +01:00
|
|
|
.order_by(desc(EmailLog.created_at))
|
2019-12-28 01:03:59 +01:00
|
|
|
.first()
|
2019-12-15 16:17:37 +01:00
|
|
|
)
|
2019-11-14 14:54:17 +01:00
|
|
|
|
2020-03-28 19:05:27 +01:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Contact {self.id} {self.website_email} {self.alias_id}>"
|
|
|
|
|
2019-11-14 14:54:17 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class EmailLog(Base, ModelMixin):
|
|
|
|
__tablename__ = "email_log"
|
2023-09-28 18:26:40 +02:00
|
|
|
__table_args__ = (Index("ix_email_log_created_at", "created_at"),)
|
2021-10-12 14:36:47 +02:00
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
contact_id = sa.Column(
|
|
|
|
sa.ForeignKey(Contact.id, ondelete="cascade"), nullable=False, index=True
|
2019-11-16 17:06:59 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=True, index=True
|
2021-07-11 12:27:30 +02:00
|
|
|
)
|
2019-11-16 17:06:59 +01:00
|
|
|
|
|
|
|
# whether this is a reply
|
2021-10-12 14:36:47 +02:00
|
|
|
is_reply = sa.Column(sa.Boolean, nullable=False, default=False)
|
2019-11-16 17:06:59 +01:00
|
|
|
|
|
|
|
# for ex if alias is disabled, this forwarding is blocked
|
2021-10-12 14:36:47 +02:00
|
|
|
blocked = sa.Column(sa.Boolean, nullable=False, default=False)
|
2019-11-16 17:06:59 +01:00
|
|
|
|
2020-10-28 11:50:14 +01:00
|
|
|
# can happen when user mailbox refuses the forwarded email
|
2020-02-22 06:53:05 +01:00
|
|
|
# usually because the forwarded email is too spammy
|
2021-10-12 14:36:47 +02:00
|
|
|
bounced = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
2020-02-22 06:53:05 +01:00
|
|
|
|
2021-03-06 17:44:08 +01:00
|
|
|
# happen when an email with auto (holiday) reply
|
2021-10-12 14:36:47 +02:00
|
|
|
auto_replied = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2021-03-06 18:10:41 +01:00
|
|
|
)
|
2021-03-06 17:44:08 +01:00
|
|
|
|
2020-03-30 21:42:25 +02:00
|
|
|
# SpamAssassin result
|
2021-10-12 14:36:47 +02:00
|
|
|
is_spam = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
|
|
|
spam_score = sa.Column(sa.Float, nullable=True)
|
|
|
|
spam_status = sa.Column(sa.Text, nullable=True, default=None)
|
2021-01-04 14:38:32 +01:00
|
|
|
# do not load this column
|
2021-10-12 14:36:47 +02:00
|
|
|
spam_report = deferred(sa.Column(sa.JSON, nullable=True))
|
2020-03-30 21:42:25 +02:00
|
|
|
|
2020-03-14 16:07:34 +01:00
|
|
|
# Point to the email that has been refused
|
2021-10-12 14:36:47 +02:00
|
|
|
refused_email_id = sa.Column(
|
|
|
|
sa.ForeignKey("refused_email.id", ondelete="SET NULL"), nullable=True
|
2020-03-14 16:07:34 +01:00
|
|
|
)
|
|
|
|
|
2020-11-24 16:35:16 +01:00
|
|
|
# in forward phase, this is the mailbox that will receive the email
|
|
|
|
# in reply phase, this is the mailbox (or a mailbox's authorized address) that sends the email
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey("mailbox.id", ondelete="cascade"), nullable=True
|
2020-11-24 16:35:16 +01:00
|
|
|
)
|
|
|
|
|
2020-05-10 18:34:57 +02:00
|
|
|
# in case of bounce, record on what mailbox the email has been bounced
|
|
|
|
# useful when an alias has several mailboxes
|
2021-10-12 14:36:47 +02:00
|
|
|
bounced_mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey("mailbox.id", ondelete="cascade"), nullable=True
|
2020-05-10 18:34:57 +02:00
|
|
|
)
|
|
|
|
|
2021-10-18 17:25:59 +02:00
|
|
|
# the Message ID
|
2021-10-27 16:06:56 +02:00
|
|
|
message_id = deferred(sa.Column(sa.String(1024), nullable=True))
|
2021-10-18 17:25:59 +02:00
|
|
|
# in the reply phase, the original message_id is replaced by the SL message_id
|
|
|
|
sl_message_id = deferred(sa.Column(sa.String(512), nullable=True))
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
refused_email = orm.relationship("RefusedEmail")
|
|
|
|
forward = orm.relationship(Contact)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
contact = orm.relationship(Contact, backref="email_logs")
|
2022-01-05 15:21:54 +01:00
|
|
|
alias = orm.relationship(Alias)
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox = orm.relationship("Mailbox", lazy="joined", foreign_keys=[mailbox_id])
|
|
|
|
user = orm.relationship(User)
|
2020-11-24 16:50:55 +01:00
|
|
|
|
2020-05-10 18:41:22 +02:00
|
|
|
def bounced_mailbox(self) -> str:
|
|
|
|
if self.bounced_mailbox_id:
|
|
|
|
return Mailbox.get(self.bounced_mailbox_id).email
|
|
|
|
# retro-compatibility
|
|
|
|
return self.contact.alias.mailboxes[0].email
|
|
|
|
|
2020-04-06 22:26:35 +02:00
|
|
|
def get_action(self) -> str:
|
|
|
|
"""return the action name: forward|reply|block|bounced"""
|
|
|
|
if self.is_reply:
|
|
|
|
return "reply"
|
|
|
|
elif self.bounced:
|
|
|
|
return "bounced"
|
|
|
|
elif self.blocked:
|
2020-04-20 19:58:10 +02:00
|
|
|
return "block"
|
2020-04-06 22:26:35 +02:00
|
|
|
else:
|
|
|
|
return "forward"
|
|
|
|
|
2021-06-02 11:38:25 +02:00
|
|
|
def get_phase(self) -> str:
|
|
|
|
if self.is_reply:
|
|
|
|
return "reply"
|
|
|
|
else:
|
|
|
|
return "forward"
|
|
|
|
|
2022-03-25 17:25:35 +01:00
|
|
|
def get_dashboard_url(self):
|
2022-06-30 11:40:01 +02:00
|
|
|
return f"{config.URL}/dashboard/refused_email?highlight_id={self.id}"
|
2022-03-25 17:25:35 +01:00
|
|
|
|
2024-02-15 15:48:02 +01:00
|
|
|
@classmethod
|
|
|
|
def create(cls, *args, **kwargs):
|
|
|
|
commit = kwargs.pop("commit", False)
|
|
|
|
email_log = super().create(*args, **kwargs)
|
|
|
|
Session.flush()
|
|
|
|
if "alias_id" in kwargs:
|
|
|
|
sql = "UPDATE alias SET last_email_log_id = :el_id WHERE id = :alias_id"
|
|
|
|
Session.execute(
|
|
|
|
sql, {"el_id": email_log.id, "alias_id": kwargs["alias_id"]}
|
|
|
|
)
|
|
|
|
if commit:
|
|
|
|
Session.commit()
|
|
|
|
return email_log
|
|
|
|
|
2020-12-29 12:17:24 +01:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<EmailLog {self.id}>"
|
|
|
|
|
2019-11-16 17:06:59 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Subscription(Base, ModelMixin):
|
2020-08-07 10:01:11 +02:00
|
|
|
"""Paddle subscription"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "subscription"
|
|
|
|
|
2019-11-14 14:54:17 +01:00
|
|
|
# Come from Paddle
|
2021-10-12 14:36:47 +02:00
|
|
|
cancel_url = sa.Column(sa.String(1024), nullable=False)
|
|
|
|
update_url = sa.Column(sa.String(1024), nullable=False)
|
|
|
|
subscription_id = sa.Column(sa.String(1024), nullable=False, unique=True)
|
|
|
|
event_time = sa.Column(ArrowType, nullable=False)
|
|
|
|
next_bill_date = sa.Column(sa.Date, nullable=False)
|
2019-11-14 14:54:17 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
cancelled = sa.Column(sa.Boolean, nullable=False, default=False)
|
2019-11-14 14:54:17 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
plan = sa.Column(sa.Enum(PlanEnum), nullable=False)
|
2019-11-14 14:54:17 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, unique=True
|
2019-11-14 14:54:17 +01:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2019-11-18 15:09:04 +01:00
|
|
|
|
2020-01-30 04:52:56 +01:00
|
|
|
def plan_name(self):
|
|
|
|
if self.plan == PlanEnum.monthly:
|
2021-12-26 22:04:45 +01:00
|
|
|
return "Monthly"
|
2020-01-30 04:52:56 +01:00
|
|
|
else:
|
2021-12-26 22:04:45 +01:00
|
|
|
return "Yearly"
|
2020-01-30 04:52:56 +01:00
|
|
|
|
2020-08-07 10:01:11 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Subscription {self.plan} {self.next_bill_date}>"
|
|
|
|
|
2019-11-18 15:09:04 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class ManualSubscription(Base, ModelMixin):
|
2020-02-23 10:31:14 +01:00
|
|
|
"""
|
|
|
|
For users who use other forms of payment and therefore not pass by Paddle
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "manual_subscription"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, unique=True
|
2020-02-23 10:31:14 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
# an reminder is sent several days before the subscription ends
|
2021-10-12 14:36:47 +02:00
|
|
|
end_at = sa.Column(ArrowType, nullable=False)
|
2020-02-23 10:31:14 +01:00
|
|
|
|
|
|
|
# for storing note about this subscription
|
2021-10-12 14:36:47 +02:00
|
|
|
comment = sa.Column(sa.Text, nullable=True)
|
2020-02-23 10:31:14 +01:00
|
|
|
|
2020-04-13 20:48:47 +02:00
|
|
|
# manual subscription are also used for Premium giveaways
|
2021-10-12 14:36:47 +02:00
|
|
|
is_giveaway = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2020-04-13 20:48:47 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2020-02-23 11:01:23 +01:00
|
|
|
|
2020-12-13 19:08:06 +01:00
|
|
|
def is_active(self):
|
|
|
|
return self.end_at > arrow.now()
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class CoinbaseSubscription(Base, ModelMixin):
|
2020-12-13 19:05:43 +01:00
|
|
|
"""
|
|
|
|
For subscriptions using Coinbase Commerce
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "coinbase_subscription"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, unique=True
|
2020-12-13 19:05:43 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
# an reminder is sent several days before the subscription ends
|
2021-10-12 14:36:47 +02:00
|
|
|
end_at = sa.Column(ArrowType, nullable=False)
|
2020-12-13 19:05:43 +01:00
|
|
|
|
|
|
|
# the Coinbase code
|
2021-10-12 14:36:47 +02:00
|
|
|
code = sa.Column(sa.String(64), nullable=True)
|
2020-12-13 19:05:43 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2020-12-13 19:05:43 +01:00
|
|
|
|
|
|
|
def is_active(self):
|
|
|
|
return self.end_at > arrow.now()
|
|
|
|
|
2020-02-23 10:31:14 +01:00
|
|
|
|
2020-04-20 23:31:25 +02:00
|
|
|
# https://help.apple.com/app-store-connect/#/dev58bda3212
|
|
|
|
_APPLE_GRACE_PERIOD_DAYS = 16
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AppleSubscription(Base, ModelMixin):
|
2020-04-18 20:47:33 +02:00
|
|
|
"""
|
|
|
|
For users who have subscribed via Apple in-app payment
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "apple_subscription"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, unique=True
|
2020-04-18 20:47:33 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
expires_date = sa.Column(ArrowType, nullable=False)
|
2020-04-18 20:47:33 +02:00
|
|
|
|
2020-04-19 23:13:07 +02:00
|
|
|
# to avoid using "Restore Purchase" on another account
|
2021-10-12 14:36:47 +02:00
|
|
|
original_transaction_id = sa.Column(sa.String(256), nullable=False, unique=True)
|
|
|
|
receipt_data = sa.Column(sa.Text(), nullable=False)
|
2020-04-18 20:47:33 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
plan = sa.Column(sa.Enum(PlanEnum), nullable=False)
|
2020-04-18 20:47:33 +02:00
|
|
|
|
2021-12-30 16:20:18 +01:00
|
|
|
# to know what subscription user has bought
|
|
|
|
# e.g. io.simplelogin.ios_app.subscription.premium.monthly
|
|
|
|
product_id = sa.Column(sa.String(256), nullable=True)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2020-04-18 20:47:33 +02:00
|
|
|
|
2020-04-19 10:58:32 +02:00
|
|
|
def is_valid(self):
|
2020-04-20 23:31:25 +02:00
|
|
|
return self.expires_date > arrow.now().shift(days=-_APPLE_GRACE_PERIOD_DAYS)
|
2020-04-19 10:58:32 +02:00
|
|
|
|
2020-04-18 20:47:33 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class DeletedAlias(Base, ModelMixin):
|
2019-11-18 15:09:04 +01:00
|
|
|
"""Store all deleted alias to make sure they are NOT reused"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "deleted_alias"
|
|
|
|
|
|
|
|
email = sa.Column(sa.String(256), unique=True, nullable=False)
|
2024-07-08 16:39:18 +02:00
|
|
|
reason = sa.Column(
|
|
|
|
IntEnumType(AliasDeleteReason),
|
|
|
|
nullable=False,
|
|
|
|
default=AliasDeleteReason.Unspecified,
|
|
|
|
server_default=str(AliasDeleteReason.Unspecified.value),
|
|
|
|
)
|
2019-11-18 15:18:53 +01:00
|
|
|
|
2020-08-14 12:02:33 +02:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
raise Exception("should use delete_alias(alias,user) instead")
|
|
|
|
|
2020-05-23 12:17:50 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Deleted Alias {self.email}>"
|
|
|
|
|
2019-11-18 15:18:53 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class EmailChange(Base, ModelMixin):
|
2019-11-18 19:32:58 +01:00
|
|
|
"""Used when user wants to update their email"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "email_change"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"),
|
2019-11-18 19:32:58 +01:00
|
|
|
nullable=False,
|
|
|
|
unique=True,
|
|
|
|
index=True,
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
new_email = sa.Column(sa.String(256), unique=True, nullable=False)
|
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
expired = sa.Column(ArrowType, nullable=False, default=_expiration_12h)
|
2019-11-18 19:32:58 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2019-11-18 19:32:58 +01:00
|
|
|
|
|
|
|
def is_expired(self):
|
|
|
|
return self.expired < arrow.now()
|
2019-11-28 23:00:19 +01:00
|
|
|
|
2020-08-13 10:59:39 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<EmailChange {self.id} {self.new_email} {self.user_id}>"
|
|
|
|
|
2019-11-28 23:00:19 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AliasUsedOn(Base, ModelMixin):
|
2019-11-28 23:00:19 +01:00
|
|
|
"""Used to know where an alias is created"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "alias_used_on"
|
|
|
|
|
2019-11-28 23:00:19 +01:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("alias_id", "hostname", name="uq_alias_used"),
|
2019-11-28 23:00:19 +01:00
|
|
|
)
|
|
|
|
|
2023-04-14 19:08:52 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
2020-03-20 12:13:00 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias = orm.relationship(Alias)
|
2019-11-28 23:00:19 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
hostname = sa.Column(sa.String(1024), nullable=False)
|
2019-11-28 23:00:19 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class ApiKey(Base, ModelMixin):
|
2019-11-28 23:00:19 +01:00
|
|
|
"""used in browser extension to identify user"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "api_key"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
name = sa.Column(sa.String(128), nullable=True)
|
|
|
|
last_used = sa.Column(ArrowType, default=None)
|
|
|
|
times = sa.Column(sa.Integer, default=0, nullable=False)
|
2022-06-23 14:26:36 +02:00
|
|
|
sudo_mode_at = sa.Column(ArrowType, default=None)
|
2019-11-28 23:00:19 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2019-11-28 23:00:19 +01:00
|
|
|
|
|
|
|
@classmethod
|
2021-09-21 11:27:37 +02:00
|
|
|
def create(cls, user_id, name=None, **kwargs):
|
|
|
|
code = random_string(60)
|
|
|
|
if cls.get_by(code=code):
|
|
|
|
code = str(uuid.uuid4())
|
2019-11-28 23:00:19 +01:00
|
|
|
|
2021-09-21 11:27:37 +02:00
|
|
|
return super().create(user_id=user_id, name=name, code=code, **kwargs)
|
2019-11-30 00:40:07 +01:00
|
|
|
|
2022-01-23 19:38:54 +01:00
|
|
|
@classmethod
|
2022-01-25 19:32:34 +01:00
|
|
|
def delete_all(cls, user_id):
|
2022-01-23 19:38:54 +01:00
|
|
|
Session.query(cls).filter(cls.user_id == user_id).delete()
|
|
|
|
|
2019-11-30 00:40:07 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class CustomDomain(Base, ModelMixin):
|
|
|
|
__tablename__ = "custom_domain"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
domain = sa.Column(sa.String(128), unique=True, nullable=False)
|
2019-11-30 00:40:07 +01:00
|
|
|
|
2020-05-03 16:05:34 +02:00
|
|
|
# default name to use when user replies/sends from alias
|
2021-10-12 14:36:47 +02:00
|
|
|
name = sa.Column(sa.String(128), nullable=True, default=None)
|
2020-05-03 16:05:34 +02:00
|
|
|
|
2021-08-17 19:02:35 +02:00
|
|
|
# mx verified
|
2021-10-12 14:36:47 +02:00
|
|
|
verified = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
|
|
dkim_verified = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2019-12-25 18:22:46 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
spf_verified = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2019-12-27 23:44:53 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
dmarc_verified = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-05-03 11:51:22 +02:00
|
|
|
)
|
2019-12-02 01:33:49 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
_mailboxes = orm.relationship("Mailbox", secondary="domain_mailbox", lazy="joined")
|
2020-08-01 12:20:59 +02:00
|
|
|
|
2019-12-30 18:17:45 +01:00
|
|
|
# an alias is created automatically the first time it receives an email
|
2021-10-12 14:36:47 +02:00
|
|
|
catch_all = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
2019-12-30 18:17:45 +01:00
|
|
|
|
2020-10-09 22:54:13 +02:00
|
|
|
# option to generate random prefix version automatically
|
2021-10-12 14:36:47 +02:00
|
|
|
random_prefix_generation = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-10-09 23:00:10 +02:00
|
|
|
)
|
2020-10-09 22:54:13 +02:00
|
|
|
|
2020-10-20 16:50:01 +02:00
|
|
|
# incremented when a check is failed on the domain
|
|
|
|
# alert when the number exceeds a threshold
|
|
|
|
# used in check_custom_domain()
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_failed_checks = sa.Column(
|
|
|
|
sa.Integer, default=0, server_default="0", nullable=False
|
2020-10-20 16:50:01 +02:00
|
|
|
)
|
|
|
|
|
2021-08-17 19:02:35 +02:00
|
|
|
# only domain has the ownership verified can go the next DNS step
|
|
|
|
# MX verified domains before this change don't have to do the TXT check
|
|
|
|
# and therefore have ownership_verified=True
|
2021-10-12 14:36:47 +02:00
|
|
|
ownership_verified = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2021-08-17 19:02:35 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
# randomly generated TXT value for verifying domain ownership
|
|
|
|
# the TXT record should be sl-verification=txt_token
|
2021-10-12 14:36:47 +02:00
|
|
|
ownership_txt_token = sa.Column(sa.String(128), nullable=True)
|
2021-08-17 19:02:35 +02:00
|
|
|
|
2021-11-05 11:29:06 +01:00
|
|
|
# if the domain is SimpleLogin subdomain, no need for the ownership, SPF, DKIM, DMARC check
|
|
|
|
is_sl_subdomain = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2024-09-17 10:30:55 +02:00
|
|
|
partner_id = sa.Column(
|
|
|
|
sa.Integer,
|
|
|
|
sa.ForeignKey("partner.id"),
|
|
|
|
nullable=True,
|
|
|
|
default=None,
|
|
|
|
server_default=None,
|
|
|
|
)
|
|
|
|
|
2024-09-19 16:20:56 +02:00
|
|
|
pending_deletion = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2021-08-17 19:02:35 +02:00
|
|
|
__table_args__ = (
|
|
|
|
Index(
|
|
|
|
"ix_unique_domain", # Index name
|
|
|
|
"domain", # Columns which are part of the index
|
|
|
|
unique=True,
|
|
|
|
postgresql_where=Column("ownership_verified"),
|
|
|
|
), # The condition
|
2024-09-30 11:52:44 +02:00
|
|
|
Index("ix_custom_domain_user_id", "user_id"),
|
|
|
|
Index("ix_custom_domain_pending_deletion", "pending_deletion"),
|
2021-08-17 19:02:35 +02:00
|
|
|
)
|
|
|
|
|
2021-12-31 11:10:36 +01:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id], backref="custom_domains")
|
2020-01-16 22:06:36 +01:00
|
|
|
|
2020-08-01 12:20:59 +02:00
|
|
|
@property
|
|
|
|
def mailboxes(self):
|
|
|
|
if self._mailboxes:
|
|
|
|
return self._mailboxes
|
|
|
|
else:
|
|
|
|
return [self.user.default_mailbox]
|
|
|
|
|
2019-12-02 01:33:49 +01:00
|
|
|
def nb_alias(self):
|
2020-03-17 11:51:40 +01:00
|
|
|
return Alias.filter_by(custom_domain_id=self.id).count()
|
2019-12-30 18:18:10 +01:00
|
|
|
|
2021-03-18 14:45:18 +01:00
|
|
|
def get_trash_url(self):
|
2022-06-30 11:40:01 +02:00
|
|
|
return config.URL + f"/dashboard/domains/{self.id}/trash"
|
2021-03-18 14:45:18 +01:00
|
|
|
|
2021-08-17 19:02:35 +02:00
|
|
|
@classmethod
|
2021-11-17 17:21:13 +01:00
|
|
|
def create(cls, **kwargs):
|
|
|
|
domain = kwargs.get("domain")
|
2023-08-03 10:20:25 +02:00
|
|
|
kwargs["domain"] = domain.replace("\n", "")
|
2021-11-17 17:21:13 +01:00
|
|
|
if DeletedSubdomain.get_by(domain=domain):
|
|
|
|
raise SubdomainInTrashError
|
|
|
|
|
|
|
|
domain: CustomDomain = super(CustomDomain, cls).create(**kwargs)
|
2021-08-17 19:02:35 +02:00
|
|
|
|
|
|
|
# generate a domain ownership txt token
|
|
|
|
if not domain.ownership_txt_token:
|
|
|
|
domain.ownership_txt_token = random_string(30)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2021-08-17 19:02:35 +02:00
|
|
|
|
2021-11-18 10:33:15 +01:00
|
|
|
if domain.is_sl_subdomain:
|
|
|
|
user = domain.user
|
|
|
|
user._subdomain_quota -= 1
|
|
|
|
Session.flush()
|
|
|
|
|
2021-08-17 19:02:35 +02:00
|
|
|
return domain
|
|
|
|
|
2021-11-17 17:21:13 +01:00
|
|
|
@classmethod
|
|
|
|
def delete(cls, obj_id):
|
|
|
|
obj: CustomDomain = cls.get(obj_id)
|
|
|
|
if obj.is_sl_subdomain:
|
|
|
|
DeletedSubdomain.create(domain=obj.domain)
|
|
|
|
|
2024-07-08 16:39:18 +02:00
|
|
|
from app import alias_utils
|
|
|
|
|
|
|
|
for alias in Alias.filter_by(custom_domain_id=obj_id):
|
|
|
|
alias_utils.delete_alias(
|
|
|
|
alias, obj.user, AliasDeleteReason.CustomDomainDeleted
|
|
|
|
)
|
|
|
|
|
2021-11-17 17:21:13 +01:00
|
|
|
return super(CustomDomain, cls).delete(obj_id)
|
|
|
|
|
2021-09-20 18:23:19 +02:00
|
|
|
@property
|
|
|
|
def auto_create_rules(self):
|
|
|
|
return sorted(self._auto_create_rules, key=lambda rule: rule.order)
|
|
|
|
|
2019-12-30 18:18:10 +01:00
|
|
|
def __repr__(self):
|
2024-07-23 16:17:23 +02:00
|
|
|
return f"<Custom Domain {self.id} {self.domain}>"
|
2020-01-01 20:02:30 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AutoCreateRule(Base, ModelMixin):
|
2021-09-20 18:23:19 +02:00
|
|
|
"""Alias auto creation rule for custom domain"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "auto_create_rule"
|
|
|
|
|
2021-09-20 18:23:19 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint(
|
2021-09-20 18:23:19 +02:00
|
|
|
"custom_domain_id", "order", name="uq_auto_create_rule_order"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
custom_domain_id = sa.Column(
|
|
|
|
sa.ForeignKey(CustomDomain.id, ondelete="cascade"), nullable=False
|
2021-09-20 18:23:19 +02:00
|
|
|
)
|
|
|
|
# an alias is auto created if it matches the regex
|
2021-10-12 14:36:47 +02:00
|
|
|
regex = sa.Column(sa.String(512), nullable=False)
|
2021-09-20 18:23:19 +02:00
|
|
|
|
|
|
|
# the order in which rules are evaluated in case there are multiple rules
|
2021-10-12 14:36:47 +02:00
|
|
|
order = sa.Column(sa.Integer, default=0, nullable=False)
|
2021-09-20 18:23:19 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
custom_domain = orm.relationship(CustomDomain, backref="_auto_create_rules")
|
2021-09-20 18:23:19 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
mailboxes = orm.relationship(
|
2021-09-20 18:23:19 +02:00
|
|
|
"Mailbox", secondary="auto_create_rule__mailbox", lazy="joined"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AutoCreateRuleMailbox(Base, ModelMixin):
|
2021-09-20 18:23:19 +02:00
|
|
|
"""store auto create rule - mailbox association"""
|
|
|
|
|
|
|
|
__tablename__ = "auto_create_rule__mailbox"
|
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint(
|
2021-09-20 18:23:19 +02:00
|
|
|
"auto_create_rule_id", "mailbox_id", name="uq_auto_create_rule_mailbox"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
auto_create_rule_id = sa.Column(
|
|
|
|
sa.ForeignKey(AutoCreateRule.id, ondelete="cascade"), nullable=False
|
2021-09-20 18:23:19 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey("mailbox.id", ondelete="cascade"), nullable=False
|
2021-09-20 18:23:19 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class DomainDeletedAlias(Base, ModelMixin):
|
2020-05-23 11:44:15 +02:00
|
|
|
"""Store all deleted alias for a domain"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "domain_deleted_alias"
|
|
|
|
|
2020-05-23 11:44:15 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("domain_id", "email", name="uq_domain_trash"),
|
2020-05-23 11:44:15 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
email = sa.Column(sa.String(256), nullable=False)
|
|
|
|
domain_id = sa.Column(
|
|
|
|
sa.ForeignKey("custom_domain.id", ondelete="cascade"), nullable=False
|
2020-05-23 11:44:15 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
2020-05-23 11:44:15 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
domain = orm.relationship(CustomDomain)
|
2022-06-10 15:44:59 +02:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id])
|
2024-07-08 16:39:18 +02:00
|
|
|
reason = sa.Column(
|
|
|
|
IntEnumType(AliasDeleteReason),
|
|
|
|
nullable=False,
|
|
|
|
default=AliasDeleteReason.Unspecified,
|
|
|
|
server_default=str(AliasDeleteReason.Unspecified.value),
|
|
|
|
)
|
2020-10-09 11:48:52 +02:00
|
|
|
|
2020-08-14 12:02:33 +02:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
raise Exception("should use delete_alias(alias,user) instead")
|
|
|
|
|
2020-10-09 11:48:52 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<DomainDeletedAlias {self.id} {self.email}>"
|
|
|
|
|
2020-05-23 11:44:15 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class LifetimeCoupon(Base, ModelMixin):
|
|
|
|
__tablename__ = "lifetime_coupon"
|
|
|
|
|
|
|
|
code = sa.Column(sa.String(128), nullable=False, unique=True)
|
|
|
|
nb_used = sa.Column(sa.Integer, nullable=False)
|
|
|
|
paid = sa.Column(sa.Boolean, default=False, server_default="0", nullable=False)
|
|
|
|
comment = sa.Column(sa.Text, nullable=True)
|
|
|
|
|
2020-01-08 21:23:41 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Coupon(Base, ModelMixin):
|
|
|
|
__tablename__ = "coupon"
|
2020-01-08 21:23:41 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
code = sa.Column(sa.String(128), nullable=False, unique=True)
|
2021-07-12 19:26:28 +02:00
|
|
|
|
|
|
|
# by default a coupon is for 1 year
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_year = sa.Column(sa.Integer, nullable=False, server_default="1", default=1)
|
2021-07-12 19:26:28 +02:00
|
|
|
|
|
|
|
# whether the coupon has been used
|
2021-10-12 14:36:47 +02:00
|
|
|
used = sa.Column(sa.Boolean, default=False, server_default="0", nullable=False)
|
2021-07-12 19:26:28 +02:00
|
|
|
|
|
|
|
# the user who uses the code
|
|
|
|
# non-null when the coupon is used
|
2021-10-12 14:36:47 +02:00
|
|
|
used_by_user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=True
|
2021-07-12 19:26:28 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
is_giveaway = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2021-09-07 15:35:55 +02:00
|
|
|
)
|
|
|
|
|
2021-11-17 11:52:46 +01:00
|
|
|
comment = sa.Column(sa.Text, nullable=True)
|
|
|
|
|
2021-11-26 18:10:23 +01:00
|
|
|
# a coupon can have an expiration
|
|
|
|
expires_date = sa.Column(ArrowType, nullable=True)
|
|
|
|
|
2021-07-12 19:26:28 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Directory(Base, ModelMixin):
|
|
|
|
__tablename__ = "directory"
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
name = sa.Column(sa.String(128), unique=True, nullable=False)
|
2020-12-07 10:48:43 +01:00
|
|
|
# when a directory is disabled, new alias can't be created on the fly
|
2021-10-12 14:36:47 +02:00
|
|
|
disabled = sa.Column(sa.Boolean, default=False, nullable=False, server_default="0")
|
2020-01-08 21:23:41 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User, backref="directories")
|
2020-01-08 21:23:41 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
_mailboxes = orm.relationship(
|
2020-06-05 22:08:08 +02:00
|
|
|
"Mailbox", secondary="directory_mailbox", lazy="joined"
|
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def mailboxes(self):
|
|
|
|
if self._mailboxes:
|
|
|
|
return self._mailboxes
|
|
|
|
else:
|
|
|
|
return [self.user.default_mailbox]
|
|
|
|
|
2020-01-08 21:23:41 +01:00
|
|
|
def nb_alias(self):
|
2020-03-17 11:51:40 +01:00
|
|
|
return Alias.filter_by(directory_id=self.id).count()
|
2020-01-08 21:23:41 +01:00
|
|
|
|
2021-11-17 17:02:31 +01:00
|
|
|
@classmethod
|
|
|
|
def create(cls, *args, **kwargs):
|
|
|
|
name = kwargs.get("name")
|
|
|
|
if DeletedDirectory.get_by(name=name):
|
|
|
|
raise DirectoryInTrashError
|
|
|
|
|
2021-11-18 10:33:15 +01:00
|
|
|
directory = super(Directory, cls).create(*args, **kwargs)
|
|
|
|
Session.flush()
|
|
|
|
|
|
|
|
user = directory.user
|
|
|
|
user._directory_quota -= 1
|
|
|
|
|
|
|
|
Session.flush()
|
|
|
|
return directory
|
2021-11-17 17:02:31 +01:00
|
|
|
|
2020-05-07 22:42:39 +02:00
|
|
|
@classmethod
|
|
|
|
def delete(cls, obj_id):
|
2020-08-14 12:02:54 +02:00
|
|
|
obj: Directory = cls.get(obj_id)
|
|
|
|
user = obj.user
|
|
|
|
# Put all aliases belonging to this directory to global or domain trash
|
2021-10-12 14:36:47 +02:00
|
|
|
for alias in Alias.filter_by(directory_id=obj_id):
|
2020-08-14 12:06:26 +02:00
|
|
|
from app import alias_utils
|
|
|
|
|
2024-07-08 16:39:18 +02:00
|
|
|
alias_utils.delete_alias(alias, user, AliasDeleteReason.DirectoryDeleted)
|
2020-05-07 22:42:39 +02:00
|
|
|
|
2021-11-17 17:02:31 +01:00
|
|
|
DeletedDirectory.create(name=obj.name)
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter(cls.id == obj_id).delete()
|
2021-11-18 10:33:15 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2020-05-07 22:50:45 +02:00
|
|
|
|
2020-01-08 21:23:41 +01:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Directory {self.name}>"
|
2020-02-03 07:09:48 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Job(Base, ModelMixin):
|
2020-02-03 07:09:48 +01:00
|
|
|
"""Used to schedule one-time job in the future"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "job"
|
|
|
|
|
|
|
|
name = sa.Column(sa.String(128), nullable=False)
|
|
|
|
payload = sa.Column(sa.JSON)
|
2020-02-03 07:09:48 +01:00
|
|
|
|
|
|
|
# whether the job has been taken by the job runner
|
2021-10-12 14:36:47 +02:00
|
|
|
taken = sa.Column(sa.Boolean, default=False, nullable=False)
|
|
|
|
run_at = sa.Column(ArrowType)
|
2022-06-28 09:22:48 +02:00
|
|
|
state = sa.Column(
|
|
|
|
sa.Integer,
|
|
|
|
nullable=False,
|
|
|
|
server_default=str(JobState.ready.value),
|
|
|
|
default=JobState.ready.value,
|
2024-03-13 14:30:17 +01:00
|
|
|
index=True,
|
2022-06-28 09:22:48 +02:00
|
|
|
)
|
|
|
|
attempts = sa.Column(sa.Integer, nullable=False, server_default="0", default=0)
|
|
|
|
taken_at = sa.Column(ArrowType, nullable=True)
|
2020-02-03 07:09:48 +01:00
|
|
|
|
2024-03-13 14:30:17 +01:00
|
|
|
__table_args__ = (Index("ix_state_run_at_taken_at", state, run_at, taken_at),)
|
|
|
|
|
2020-02-03 07:09:48 +01:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Job {self.id} {self.name} {self.payload}>"
|
2020-02-10 17:11:09 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Mailbox(Base, ModelMixin):
|
|
|
|
__tablename__ = "mailbox"
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
email = sa.Column(sa.String(256), nullable=False, index=True)
|
|
|
|
verified = sa.Column(sa.Boolean, default=False, nullable=False)
|
|
|
|
force_spf = sa.Column(sa.Boolean, default=True, server_default="1", nullable=False)
|
2020-02-10 17:11:09 +01:00
|
|
|
|
2020-02-23 08:02:02 +01:00
|
|
|
# used when user wants to update mailbox email
|
2021-10-12 14:36:47 +02:00
|
|
|
new_email = sa.Column(sa.String(256), unique=True)
|
2020-02-23 08:02:02 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
pgp_public_key = sa.Column(sa.Text, nullable=True)
|
|
|
|
pgp_finger_print = sa.Column(sa.String(512), nullable=True)
|
|
|
|
disable_pgp = sa.Column(
|
|
|
|
sa.Boolean, default=False, nullable=False, server_default="0"
|
2020-11-24 11:15:07 +01:00
|
|
|
)
|
2020-03-08 11:55:39 +01:00
|
|
|
|
2020-06-28 11:17:36 +02:00
|
|
|
# incremented when a check is failed on the mailbox
|
|
|
|
# alert when the number exceeds a threshold
|
|
|
|
# used in sanity_check()
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_failed_checks = sa.Column(
|
|
|
|
sa.Integer, default=0, server_default="0", nullable=False
|
2020-06-28 11:17:36 +02:00
|
|
|
)
|
|
|
|
|
2020-10-12 13:28:21 +02:00
|
|
|
# a mailbox can be disabled if it can't be reached
|
2021-10-12 14:36:47 +02:00
|
|
|
disabled = sa.Column(sa.Boolean, default=False, nullable=False, server_default="0")
|
2020-10-12 13:28:21 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
generic_subject = sa.Column(sa.String(78), nullable=True)
|
2020-11-07 12:48:44 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__table_args__ = (sa.UniqueConstraint("user_id", "email", name="uq_mailbox_user"),)
|
2020-05-07 21:46:16 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id])
|
2020-06-09 17:02:45 +02:00
|
|
|
|
2020-11-24 11:18:16 +01:00
|
|
|
def pgp_enabled(self) -> bool:
|
|
|
|
if self.pgp_finger_print and not self.disable_pgp:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2020-02-10 17:11:09 +01:00
|
|
|
def nb_alias(self):
|
2024-04-30 16:41:47 +02:00
|
|
|
alias_ids = set(
|
|
|
|
am.alias_id
|
|
|
|
for am in AliasMailbox.filter_by(mailbox_id=self.id).values(
|
|
|
|
AliasMailbox.alias_id
|
|
|
|
)
|
2020-06-03 09:06:38 +02:00
|
|
|
)
|
2024-04-30 16:41:47 +02:00
|
|
|
for alias in Alias.filter_by(mailbox_id=self.id).values(Alias.id):
|
|
|
|
alias_ids.add(alias.id)
|
|
|
|
return len(alias_ids)
|
2020-02-10 17:11:09 +01:00
|
|
|
|
2023-08-09 09:56:53 +02:00
|
|
|
def is_proton(self) -> bool:
|
|
|
|
if (
|
|
|
|
self.email.endswith("@proton.me")
|
|
|
|
or self.email.endswith("@protonmail.com")
|
|
|
|
or self.email.endswith("@protonmail.ch")
|
2023-09-04 21:21:39 +02:00
|
|
|
or self.email.endswith("@proton.ch")
|
2023-08-09 09:56:53 +02:00
|
|
|
or self.email.endswith("@pm.me")
|
|
|
|
):
|
|
|
|
return True
|
|
|
|
|
|
|
|
from app.email_utils import get_email_local_part
|
|
|
|
|
2024-10-02 15:46:10 +02:00
|
|
|
mx_domains = get_mx_domains(get_email_local_part(self.email))
|
2023-08-09 09:56:53 +02:00
|
|
|
# Proton is the first domain
|
2024-10-02 15:46:10 +02:00
|
|
|
if mx_domains and mx_domains[0].domain in (
|
2023-08-09 09:56:53 +02:00
|
|
|
"mail.protonmail.ch.",
|
|
|
|
"mailsec.protonmail.ch.",
|
|
|
|
):
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2020-05-07 22:40:53 +02:00
|
|
|
@classmethod
|
|
|
|
def delete(cls, obj_id):
|
2020-08-14 12:03:41 +02:00
|
|
|
mailbox: Mailbox = cls.get(obj_id)
|
|
|
|
user = mailbox.user
|
|
|
|
|
|
|
|
# Put all aliases belonging to this mailbox to global or domain trash
|
2021-10-12 14:36:47 +02:00
|
|
|
for alias in Alias.filter_by(mailbox_id=obj_id):
|
2020-08-14 12:03:41 +02:00
|
|
|
# special handling for alias that has several mailboxes and has mailbox_id=obj_id
|
|
|
|
if len(alias.mailboxes) > 1:
|
|
|
|
# use the first mailbox found in alias._mailboxes
|
|
|
|
first_mb = alias._mailboxes[0]
|
|
|
|
alias.mailbox_id = first_mb.id
|
|
|
|
alias._mailboxes.remove(first_mb)
|
|
|
|
else:
|
2020-08-14 12:06:26 +02:00
|
|
|
from app import alias_utils
|
|
|
|
|
2020-08-14 12:03:41 +02:00
|
|
|
# only put aliases that have mailbox as a single mailbox into trash
|
2024-07-08 16:39:18 +02:00
|
|
|
alias_utils.delete_alias(alias, user, AliasDeleteReason.MailboxDeleted)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2020-05-07 22:40:53 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter(cls.id == obj_id).delete()
|
|
|
|
Session.commit()
|
2020-05-07 22:50:45 +02:00
|
|
|
|
2020-06-09 17:02:45 +02:00
|
|
|
@property
|
|
|
|
def aliases(self) -> [Alias]:
|
2024-04-30 16:41:47 +02:00
|
|
|
ret = dict(
|
|
|
|
(alias.id, alias) for alias in Alias.filter_by(mailbox_id=self.id).all()
|
|
|
|
)
|
2020-06-09 17:02:45 +02:00
|
|
|
|
|
|
|
for am in AliasMailbox.filter_by(mailbox_id=self.id):
|
2024-04-30 16:41:47 +02:00
|
|
|
if am.alias_id not in ret:
|
|
|
|
ret[am.alias_id] = am.alias
|
2020-06-09 17:02:45 +02:00
|
|
|
|
2024-04-30 16:41:47 +02:00
|
|
|
return list(ret.values())
|
2020-06-09 17:02:45 +02:00
|
|
|
|
2023-08-03 10:20:25 +02:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
if "email" in kw:
|
|
|
|
kw["email"] = sanitize_email(kw["email"])
|
|
|
|
return super().create(**kw)
|
|
|
|
|
2020-02-10 17:11:09 +01:00
|
|
|
def __repr__(self):
|
2020-11-26 10:08:09 +01:00
|
|
|
return f"<Mailbox {self.id} {self.email}>"
|
2020-02-28 13:00:45 +01:00
|
|
|
|
|
|
|
|
2024-07-30 13:36:48 +02:00
|
|
|
class MailboxActivation(Base, ModelMixin):
|
|
|
|
__tablename__ = "mailbox_activation"
|
|
|
|
|
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
|
|
|
code = sa.Column(sa.String(32), nullable=False, index=True)
|
|
|
|
tries = sa.Column(sa.Integer, default=0, nullable=False)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AccountActivation(Base, ModelMixin):
|
2020-02-28 13:00:45 +01:00
|
|
|
"""contains code to activate the user account when they sign up on mobile"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "account_activation"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, unique=True
|
2020-02-28 13:00:45 +01:00
|
|
|
)
|
|
|
|
# the activation code is usually 6 digits
|
2021-10-12 14:36:47 +02:00
|
|
|
code = sa.Column(sa.String(10), nullable=False)
|
2020-02-28 13:00:45 +01:00
|
|
|
|
|
|
|
# nb tries decrements each time user enters wrong code
|
2021-10-12 14:36:47 +02:00
|
|
|
tries = sa.Column(sa.Integer, default=3, nullable=False)
|
2020-02-28 13:00:45 +01:00
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
CheckConstraint(tries >= 0, name="account_activation_tries_positive"),
|
|
|
|
{},
|
|
|
|
)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class RefusedEmail(Base, ModelMixin):
|
2020-03-14 16:07:34 +01:00
|
|
|
"""Store emails that have been refused, i.e. bounced or classified as spams"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "refused_email"
|
|
|
|
|
2020-03-14 16:07:34 +01:00
|
|
|
# Store the full report, including logs from Sending & Receiving MTA
|
2021-10-12 14:36:47 +02:00
|
|
|
full_report_path = sa.Column(sa.String(128), unique=True, nullable=False)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
|
|
|
# The original email, to display to user
|
2021-10-12 14:36:47 +02:00
|
|
|
path = sa.Column(sa.String(128), unique=True, nullable=True)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
|
|
|
# the email content will be deleted at this date
|
2021-10-12 14:36:47 +02:00
|
|
|
delete_at = sa.Column(ArrowType, nullable=False, default=_expiration_7d)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
2020-03-15 11:10:37 +01:00
|
|
|
# toggle this when email content (stored at full_report_path & path are deleted)
|
2021-10-12 14:36:47 +02:00
|
|
|
deleted = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
2020-03-15 11:10:37 +01:00
|
|
|
|
2020-03-14 16:07:34 +01:00
|
|
|
def get_url(self, expires_in=3600):
|
2020-03-22 16:51:21 +01:00
|
|
|
if self.path:
|
|
|
|
return s3.get_url(self.path, expires_in)
|
|
|
|
else:
|
|
|
|
return s3.get_url(self.full_report_path, expires_in)
|
2020-03-14 16:07:34 +01:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"<Refused Email {self.id} {self.path} {self.delete_at}>"
|
2020-04-09 22:19:45 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Referral(Base, ModelMixin):
|
2020-04-09 22:19:45 +02:00
|
|
|
"""Referral code so user can invite others"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "referral"
|
2020-04-09 22:19:45 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
name = sa.Column(sa.String(512), nullable=True, default=None)
|
2020-04-09 22:19:45 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
|
2021-10-26 11:55:27 +02:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id], backref="referrals")
|
2020-06-03 09:06:38 +02:00
|
|
|
|
2021-05-10 15:51:39 +02:00
|
|
|
@property
|
2020-07-02 08:48:37 +02:00
|
|
|
def nb_user(self) -> int:
|
2020-04-09 22:19:45 +02:00
|
|
|
return User.filter_by(referral_id=self.id, activated=True).count()
|
|
|
|
|
2021-05-10 15:51:39 +02:00
|
|
|
@property
|
2020-07-02 08:48:37 +02:00
|
|
|
def nb_paid_user(self) -> int:
|
|
|
|
res = 0
|
|
|
|
for user in User.filter_by(referral_id=self.id, activated=True):
|
|
|
|
if user.is_paid():
|
|
|
|
res += 1
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
2020-04-09 22:19:45 +02:00
|
|
|
def link(self):
|
2022-06-30 11:40:01 +02:00
|
|
|
return f"{config.LANDING_PAGE_URL}?slref={self.code}"
|
2020-05-09 20:40:36 +02:00
|
|
|
|
2021-10-25 15:02:02 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return f"<Referral {self.code}>"
|
|
|
|
|
2020-05-09 20:40:36 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class SentAlert(Base, ModelMixin):
|
2020-05-09 20:40:36 +02:00
|
|
|
"""keep track of alerts sent to user.
|
|
|
|
User can receive an alert when there's abnormal activity on their aliases such as
|
|
|
|
- reverse-alias not used by the owning mailbox
|
|
|
|
- SPF fails when using the reverse-alias
|
|
|
|
- bounced email
|
|
|
|
- ...
|
|
|
|
|
|
|
|
Different rate controls can then be implemented based on SentAlert:
|
|
|
|
- only once alert: an alert type should be sent only once
|
|
|
|
- max number of sent per 24H: an alert type should not be sent more than X times in 24h
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "sent_alert"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
to_email = sa.Column(sa.String(256), nullable=False)
|
|
|
|
alert_type = sa.Column(sa.String(256), nullable=False)
|
2020-05-03 15:54:19 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AliasMailbox(Base, ModelMixin):
|
|
|
|
__tablename__ = "alias_mailbox"
|
2020-05-03 15:54:19 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("alias_id", "mailbox_id", name="uq_alias_mailbox"),
|
2020-05-03 15:54:19 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=False, index=True
|
2020-12-02 17:32:42 +01:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False, index=True
|
2020-05-03 15:54:19 +02:00
|
|
|
)
|
2020-05-17 09:59:07 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias = orm.relationship(Alias)
|
2020-06-09 17:02:45 +02:00
|
|
|
|
2020-05-17 09:59:07 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AliasHibp(Base, ModelMixin):
|
2021-05-13 22:44:16 +02:00
|
|
|
__tablename__ = "alias_hibp"
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__table_args__ = (sa.UniqueConstraint("alias_id", "hibp_id", name="uq_alias_hibp"),)
|
2021-05-13 22:44:16 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias_id = sa.Column(
|
|
|
|
sa.Integer(), sa.ForeignKey("alias.id", ondelete="cascade"), index=True
|
2021-05-28 19:59:26 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
hibp_id = sa.Column(
|
|
|
|
sa.Integer(), sa.ForeignKey("hibp.id", ondelete="cascade"), index=True
|
2021-05-28 19:59:26 +02:00
|
|
|
)
|
2021-05-13 22:44:16 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
alias = orm.relationship(
|
|
|
|
"Alias", backref=orm.backref("alias_hibp", cascade="all, delete-orphan")
|
2021-05-14 19:59:32 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
hibp = orm.relationship(
|
|
|
|
"Hibp", backref=orm.backref("alias_hibp", cascade="all, delete-orphan")
|
2021-05-14 19:59:32 +02:00
|
|
|
)
|
2021-05-13 22:44:16 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class DirectoryMailbox(Base, ModelMixin):
|
|
|
|
__tablename__ = "directory_mailbox"
|
2020-06-05 22:08:08 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("directory_id", "mailbox_id", name="uq_directory_mailbox"),
|
2020-06-05 22:08:08 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
directory_id = sa.Column(
|
|
|
|
sa.ForeignKey(Directory.id, ondelete="cascade"), nullable=False
|
2020-06-05 22:08:08 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False
|
2020-06-05 22:08:08 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class DomainMailbox(Base, ModelMixin):
|
2020-08-01 12:20:59 +02:00
|
|
|
"""store the owning mailboxes for a domain"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "domain_mailbox"
|
|
|
|
|
2020-08-01 12:20:59 +02:00
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("domain_id", "mailbox_id", name="uq_domain_mailbox"),
|
2020-08-01 12:20:59 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
domain_id = sa.Column(
|
|
|
|
sa.ForeignKey(CustomDomain.id, ondelete="cascade"), nullable=False
|
2020-08-01 12:20:59 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False
|
2020-08-01 12:20:59 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-05-17 09:59:07 +02:00
|
|
|
_NB_RECOVERY_CODE = 8
|
|
|
|
_RECOVERY_CODE_LENGTH = 8
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class RecoveryCode(Base, ModelMixin):
|
2020-05-17 09:59:07 +02:00
|
|
|
"""allow user to login in case you lose any of your authenticators"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "recovery_code"
|
|
|
|
__table_args__ = (sa.UniqueConstraint("user_id", "code", name="uq_recovery_code"),)
|
2020-05-17 09:59:07 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
2022-10-03 12:32:45 +02:00
|
|
|
code = sa.Column(sa.String(64), nullable=False)
|
2021-10-12 14:36:47 +02:00
|
|
|
used = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
|
|
used_at = sa.Column(ArrowType, nullable=True, default=None)
|
2020-05-17 09:59:07 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2020-05-17 09:59:07 +02:00
|
|
|
|
2022-10-03 12:32:45 +02:00
|
|
|
@classmethod
|
|
|
|
def _hash_code(cls, code: str) -> str:
|
|
|
|
code_hmac = hmac.new(
|
|
|
|
config.RECOVERY_CODE_HMAC_SECRET.encode("utf-8"),
|
|
|
|
code.encode("utf-8"),
|
|
|
|
"sha3_224",
|
|
|
|
)
|
|
|
|
return base64.urlsafe_b64encode(code_hmac.digest()).decode("utf-8").rstrip("=")
|
|
|
|
|
2020-05-17 09:59:07 +02:00
|
|
|
@classmethod
|
|
|
|
def generate(cls, user):
|
|
|
|
"""generate recovery codes for user"""
|
|
|
|
# delete all existing codes
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter_by(user_id=user.id).delete()
|
|
|
|
Session.flush()
|
2020-05-17 09:59:07 +02:00
|
|
|
|
|
|
|
nb_code = 0
|
2022-10-03 12:32:45 +02:00
|
|
|
raw_codes = []
|
2020-05-17 09:59:07 +02:00
|
|
|
while nb_code < _NB_RECOVERY_CODE:
|
2022-10-03 12:32:45 +02:00
|
|
|
raw_code = random_string(_RECOVERY_CODE_LENGTH)
|
|
|
|
encoded_code = cls._hash_code(raw_code)
|
|
|
|
if not cls.get_by(user_id=user.id, code=encoded_code):
|
|
|
|
cls.create(user_id=user.id, code=encoded_code)
|
|
|
|
raw_codes.append(raw_code)
|
2020-05-17 09:59:07 +02:00
|
|
|
nb_code += 1
|
|
|
|
|
|
|
|
LOG.d("Create recovery codes for %s", user)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2022-10-03 12:32:45 +02:00
|
|
|
return raw_codes
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def find_by_user_code(cls, user: User, code: str):
|
|
|
|
hashed_code = cls._hash_code(code)
|
2024-06-26 18:26:46 +02:00
|
|
|
return cls.get_by(user_id=user.id, code=hashed_code)
|
2020-05-17 10:04:54 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def empty(cls, user):
|
|
|
|
"""Delete all recovery codes for user"""
|
2021-10-12 14:36:47 +02:00
|
|
|
cls.filter_by(user_id=user.id).delete()
|
|
|
|
Session.commit()
|
2020-05-23 18:50:36 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Notification(Base, ModelMixin):
|
|
|
|
__tablename__ = "notification"
|
2024-03-13 14:30:17 +01:00
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey(User.id, ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
message = sa.Column(sa.Text, nullable=False)
|
2022-01-24 15:18:56 +01:00
|
|
|
title = sa.Column(sa.String(512))
|
2020-05-23 18:50:36 +02:00
|
|
|
|
|
|
|
# whether user has marked the notification as read
|
2021-10-12 14:36:47 +02:00
|
|
|
read = sa.Column(sa.Boolean, nullable=False, default=False)
|
2020-07-04 23:18:11 +02:00
|
|
|
|
2022-01-24 16:10:36 +01:00
|
|
|
@staticmethod
|
|
|
|
def render(template_name, **kwargs) -> str:
|
2022-06-30 11:40:01 +02:00
|
|
|
templates_dir = os.path.join(config.ROOT_DIR, "templates")
|
2022-01-24 16:10:36 +01:00
|
|
|
env = Environment(loader=FileSystemLoader(templates_dir))
|
|
|
|
|
|
|
|
template = env.get_template(template_name)
|
|
|
|
|
|
|
|
return template.render(
|
2022-06-30 11:40:01 +02:00
|
|
|
URL=config.URL,
|
|
|
|
LANDING_PAGE_URL=config.LANDING_PAGE_URL,
|
2022-01-24 16:10:36 +01:00
|
|
|
YEAR=arrow.now().year,
|
|
|
|
**kwargs,
|
|
|
|
)
|
|
|
|
|
2020-07-04 23:18:11 +02:00
|
|
|
|
2023-04-04 15:21:51 +02:00
|
|
|
class Partner(Base, ModelMixin):
|
|
|
|
__tablename__ = "partner"
|
|
|
|
|
|
|
|
name = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
contact_email = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def find_by_token(token: str) -> Optional[Partner]:
|
|
|
|
hmaced = PartnerApiToken.hmac_token(token)
|
|
|
|
res = (
|
|
|
|
Session.query(Partner, PartnerApiToken)
|
|
|
|
.filter(
|
|
|
|
and_(
|
|
|
|
PartnerApiToken.token == hmaced,
|
|
|
|
Partner.id == PartnerApiToken.partner_id,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.first()
|
|
|
|
)
|
|
|
|
if res:
|
|
|
|
partner, partner_api_token = res
|
|
|
|
return partner
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class SLDomain(Base, ModelMixin):
|
2020-10-15 16:08:06 +02:00
|
|
|
"""SimpleLogin domains"""
|
2020-07-04 23:18:11 +02:00
|
|
|
|
2020-10-15 16:51:07 +02:00
|
|
|
__tablename__ = "public_domain"
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
domain = sa.Column(sa.String(128), unique=True, nullable=False)
|
2020-08-15 13:15:20 +02:00
|
|
|
|
2020-10-15 16:08:06 +02:00
|
|
|
# only available for premium accounts
|
2021-10-12 14:36:47 +02:00
|
|
|
premium_only = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
2020-10-15 16:08:06 +02:00
|
|
|
)
|
|
|
|
|
2021-11-05 11:29:06 +01:00
|
|
|
# if True, the domain can be used for the subdomain feature
|
|
|
|
can_use_subdomain = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2023-04-04 15:21:51 +02:00
|
|
|
partner_id = sa.Column(
|
|
|
|
sa.ForeignKey(Partner.id, ondelete="cascade"),
|
|
|
|
nullable=True,
|
|
|
|
default=None,
|
2023-04-20 11:06:59 +02:00
|
|
|
server_default="NULL",
|
2023-04-04 15:21:51 +02:00
|
|
|
)
|
|
|
|
|
2022-06-22 18:21:19 +02:00
|
|
|
# if enabled, do not show this domain when user creates a custom alias
|
|
|
|
hidden = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
|
|
|
|
|
|
|
# the order in which the domains are shown when user creates a custom alias
|
|
|
|
order = sa.Column(sa.Integer, nullable=False, default=0, server_default="0")
|
|
|
|
|
2023-04-20 12:14:53 +02:00
|
|
|
use_as_reverse_alias = sa.Column(
|
|
|
|
sa.Boolean, nullable=False, default=False, server_default="0"
|
|
|
|
)
|
|
|
|
|
2020-10-15 16:08:06 +02:00
|
|
|
def __repr__(self):
|
2024-07-23 16:17:23 +02:00
|
|
|
return f"<SLDomain {self.id} {self.domain} {'Premium' if self.premium_only else 'Free'}>"
|
2020-10-15 16:08:06 +02:00
|
|
|
|
2020-08-15 13:15:20 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Monitoring(Base, ModelMixin):
|
2020-08-15 13:15:20 +02:00
|
|
|
"""
|
|
|
|
Store different host information over the time in order to
|
|
|
|
- alert issues in (almost) real time
|
|
|
|
- analyze data trending
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "monitoring"
|
|
|
|
|
|
|
|
host = sa.Column(sa.String(256), nullable=False)
|
2020-08-15 13:15:20 +02:00
|
|
|
|
|
|
|
# Postfix stats
|
2021-10-12 14:36:47 +02:00
|
|
|
incoming_queue = sa.Column(sa.Integer, nullable=False)
|
|
|
|
active_queue = sa.Column(sa.Integer, nullable=False)
|
|
|
|
deferred_queue = sa.Column(sa.Integer, nullable=False)
|
2020-09-10 20:05:25 +02:00
|
|
|
|
2023-07-29 10:03:31 +02:00
|
|
|
__table_args__ = (Index("ix_monitoring_created_at", "created_at"),)
|
|
|
|
|
2020-09-10 20:05:25 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class BatchImport(Base, ModelMixin):
|
|
|
|
__tablename__ = "batch_import"
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
file_id = sa.Column(sa.ForeignKey(File.id, ondelete="cascade"), nullable=False)
|
|
|
|
processed = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
|
|
summary = sa.Column(sa.Text, nullable=True, default=None)
|
2020-09-10 20:05:25 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
file = orm.relationship(File)
|
|
|
|
user = orm.relationship(User)
|
2020-09-10 20:05:25 +02:00
|
|
|
|
|
|
|
def nb_alias(self):
|
2021-10-12 14:36:47 +02:00
|
|
|
return Alias.filter_by(batch_import_id=self.id).count()
|
2020-09-10 20:05:25 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"<BatchImport {self.id}>"
|
2020-09-28 17:40:54 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class AuthorizedAddress(Base, ModelMixin):
|
2020-09-28 17:40:54 +02:00
|
|
|
"""Authorize other addresses to send emails from aliases that are owned by a mailbox"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "authorized_address"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
mailbox_id = sa.Column(
|
|
|
|
sa.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False
|
2020-09-28 17:40:54 +02:00
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
email = sa.Column(sa.String(256), nullable=False)
|
2020-09-28 17:40:54 +02:00
|
|
|
|
|
|
|
__table_args__ = (
|
2021-10-12 14:36:47 +02:00
|
|
|
sa.UniqueConstraint("mailbox_id", "email", name="uq_authorize_address"),
|
2020-09-28 17:40:54 +02:00
|
|
|
)
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
mailbox = orm.relationship(Mailbox, backref="authorized_addresses")
|
2020-09-28 17:40:54 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"<AuthorizedAddress {self.id} {self.email} {self.mailbox_id}>"
|
2021-01-25 18:47:02 +01:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Metric2(Base, ModelMixin):
|
2021-03-23 10:23:40 +01:00
|
|
|
"""
|
|
|
|
For storing different metrics like number of users, etc
|
|
|
|
Store each metric as a column as opposed to having different rows as in Metric
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "metric2"
|
|
|
|
date = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_user = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_activated_user = sa.Column(sa.Float, nullable=True)
|
2022-07-04 11:40:29 +02:00
|
|
|
nb_proton_user = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_premium = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_apple_premium = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_cancelled_premium = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_manual_premium = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_coinbase_premium = sa.Column(sa.Float, nullable=True)
|
2022-07-04 11:40:29 +02:00
|
|
|
nb_proton_premium = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
|
|
|
# nb users who have been referred
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_referred_user = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_referred_user_paid = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_alias = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-07-28 18:31:59 +02:00
|
|
|
# Obsolete as only for the last 14 days
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_forward = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_block = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_reply = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_bounced = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_spam = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-07-28 18:31:59 +02:00
|
|
|
# should be used instead
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_forward_last_24h = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_block_last_24h = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_reply_last_24h = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_bounced_last_24h = sa.Column(sa.Float, nullable=True)
|
2021-10-15 10:46:22 +02:00
|
|
|
# includes bounces for both forwarding and transactional email
|
|
|
|
nb_total_bounced_last_24h = sa.Column(sa.Float, nullable=True)
|
2021-07-28 18:31:59 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_verified_custom_domain = sa.Column(sa.Float, nullable=True)
|
2021-11-17 17:43:59 +01:00
|
|
|
nb_subdomain = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_directory = sa.Column(sa.Float, nullable=True)
|
|
|
|
|
|
|
|
nb_deleted_directory = sa.Column(sa.Float, nullable=True)
|
|
|
|
nb_deleted_subdomain = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
nb_app = sa.Column(sa.Float, nullable=True)
|
2021-03-23 10:23:40 +01:00
|
|
|
|
|
|
|
|
2022-10-14 17:35:34 +02:00
|
|
|
class DailyMetric(Base, ModelMixin):
|
|
|
|
"""
|
|
|
|
For storing daily event-based metrics.
|
|
|
|
The difference between DailyEventMetric and Metric2 is Metric2 stores the total
|
|
|
|
whereas DailyEventMetric is reset for a new day
|
|
|
|
"""
|
|
|
|
|
|
|
|
__tablename__ = "daily_metric"
|
|
|
|
date = sa.Column(sa.Date, nullable=False, unique=True)
|
|
|
|
|
|
|
|
# users who sign up via web without using "Login with Proton"
|
|
|
|
nb_new_web_non_proton_user = sa.Column(
|
|
|
|
sa.Integer, nullable=False, server_default="0", default=0
|
|
|
|
)
|
|
|
|
|
|
|
|
nb_alias = sa.Column(sa.Integer, nullable=False, server_default="0", default=0)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_or_create_today_metric() -> DailyMetric:
|
|
|
|
today = arrow.utcnow().date()
|
|
|
|
daily_metric = DailyMetric.get_by(date=today)
|
|
|
|
if not daily_metric:
|
|
|
|
daily_metric = DailyMetric.create(
|
|
|
|
date=today, nb_new_web_non_proton_user=0, nb_alias=0
|
|
|
|
)
|
|
|
|
return daily_metric
|
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Bounce(Base, ModelMixin):
|
2021-01-26 09:59:08 +01:00
|
|
|
"""Record all bounces. Deleted after 7 days"""
|
2021-01-26 09:54:26 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "bounce"
|
|
|
|
email = sa.Column(sa.String(256), nullable=False, index=True)
|
2021-10-14 15:45:29 +02:00
|
|
|
info = sa.Column(sa.Text, nullable=True)
|
2021-01-26 09:54:26 +01:00
|
|
|
|
2023-07-29 10:03:31 +02:00
|
|
|
__table_args__ = (sa.Index("ix_bounce_created_at", "created_at"),)
|
|
|
|
|
2021-01-26 09:54:26 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class TransactionalEmail(Base, ModelMixin):
|
2021-01-26 09:54:26 +01:00
|
|
|
"""Storing all email addresses that receive transactional emails, including account email and mailboxes.
|
|
|
|
Deleted after 7 days
|
|
|
|
"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "transactional_email"
|
|
|
|
email = sa.Column(sa.String(256), nullable=False, unique=False)
|
2021-05-10 13:03:19 +02:00
|
|
|
|
2023-07-29 10:03:31 +02:00
|
|
|
__table_args__ = (sa.Index("ix_transactional_email_created_at", "created_at"),)
|
|
|
|
|
2024-02-27 16:52:45 +01:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
# whether to call Session.commit
|
|
|
|
commit = kw.pop("commit", False)
|
|
|
|
|
|
|
|
r = cls(**kw)
|
|
|
|
if not config.STORE_TRANSACTIONAL_EMAILS:
|
|
|
|
return r
|
|
|
|
|
|
|
|
Session.add(r)
|
|
|
|
if commit:
|
|
|
|
Session.commit()
|
|
|
|
return r
|
|
|
|
|
2021-05-10 13:03:19 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class Payout(Base, ModelMixin):
|
2021-05-10 13:03:19 +02:00
|
|
|
"""Referral payouts"""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "payout"
|
|
|
|
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=False)
|
2021-05-10 13:03:19 +02:00
|
|
|
|
|
|
|
# in USD
|
2021-10-12 14:36:47 +02:00
|
|
|
amount = sa.Column(sa.Float, nullable=False)
|
2021-05-10 13:03:19 +02:00
|
|
|
|
|
|
|
# BTC, PayPal, etc
|
2021-10-12 14:36:47 +02:00
|
|
|
payment_method = sa.Column(sa.String(256), nullable=False)
|
2021-05-10 13:03:19 +02:00
|
|
|
|
|
|
|
# number of upgraded user included in this payout
|
2021-10-12 14:36:47 +02:00
|
|
|
number_upgraded_account = sa.Column(sa.Integer, nullable=False)
|
2021-05-10 13:03:19 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
comment = sa.Column(sa.Text)
|
2021-05-10 15:51:39 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
user = orm.relationship(User)
|
2021-06-22 17:52:24 +02:00
|
|
|
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
class IgnoredEmail(Base, ModelMixin):
|
2021-06-22 17:52:24 +02:00
|
|
|
"""If an email has mail_from and rcpt_to present in this table, discard it by returning 250 status."""
|
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
__tablename__ = "ignored_email"
|
2021-08-02 11:30:29 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
mail_from = sa.Column(sa.String(512), nullable=False)
|
|
|
|
rcpt_to = sa.Column(sa.String(512), nullable=False)
|
2021-08-02 11:30:29 +02:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
|
|
|
|
class IgnoreBounceSender(Base, ModelMixin):
|
2021-08-02 11:30:29 +02:00
|
|
|
"""Ignore sender that doesn't correctly handle bounces, for example noreply@github.com"""
|
|
|
|
|
2021-10-13 10:52:41 +02:00
|
|
|
__tablename__ = "ignore_bounce_sender"
|
2021-10-12 14:36:47 +02:00
|
|
|
|
|
|
|
mail_from = sa.Column(sa.String(512), nullable=False, unique=True)
|
2021-08-02 11:30:29 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"<NoReplySender {self.mail_from}"
|
2021-10-18 17:25:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
class MessageIDMatching(Base, ModelMixin):
|
|
|
|
"""Store the SL Message ID and the original Message ID"""
|
|
|
|
|
|
|
|
__tablename__ = "message_id_matching"
|
|
|
|
|
|
|
|
# SimpleLogin Message ID
|
|
|
|
sl_message_id = sa.Column(sa.String(512), unique=True, nullable=False)
|
2021-10-27 16:06:56 +02:00
|
|
|
original_message_id = sa.Column(sa.String(1024), unique=True, nullable=False)
|
2021-11-01 18:41:36 +01:00
|
|
|
|
|
|
|
# to track what email_log that has created this matching
|
|
|
|
email_log_id = sa.Column(
|
2023-10-05 10:55:29 +02:00
|
|
|
sa.ForeignKey("email_log.id", ondelete="cascade"), nullable=True, index=True
|
2021-11-01 18:41:36 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
email_log = orm.relationship("EmailLog")
|
2021-11-17 17:01:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
class DeletedDirectory(Base, ModelMixin):
|
|
|
|
"""To avoid directory from being reused"""
|
|
|
|
|
|
|
|
__tablename__ = "deleted_directory"
|
|
|
|
|
|
|
|
name = sa.Column(sa.String(128), unique=True, nullable=False)
|
2021-11-17 17:20:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
class DeletedSubdomain(Base, ModelMixin):
|
|
|
|
"""To avoid directory from being reused"""
|
|
|
|
|
|
|
|
__tablename__ = "deleted_subdomain"
|
|
|
|
|
|
|
|
domain = sa.Column(sa.String(128), unique=True, nullable=False)
|
2021-12-02 16:50:26 +01:00
|
|
|
|
|
|
|
|
2022-01-03 10:31:33 +01:00
|
|
|
class InvalidMailboxDomain(Base, ModelMixin):
|
|
|
|
"""Domains that can't be used as mailbox"""
|
|
|
|
|
|
|
|
__tablename__ = "invalid_mailbox_domain"
|
|
|
|
|
|
|
|
domain = sa.Column(sa.String(256), unique=True, nullable=False)
|
|
|
|
|
|
|
|
|
2021-12-02 16:50:26 +01:00
|
|
|
# region Phone
|
|
|
|
class PhoneCountry(Base, ModelMixin):
|
|
|
|
__tablename__ = "phone_country"
|
|
|
|
|
|
|
|
name = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
|
|
|
|
|
|
|
|
class PhoneNumber(Base, ModelMixin):
|
|
|
|
__tablename__ = "phone_number"
|
|
|
|
|
|
|
|
country_id = sa.Column(
|
|
|
|
sa.ForeignKey(PhoneCountry.id, ondelete="cascade"), nullable=False
|
|
|
|
)
|
|
|
|
|
|
|
|
# with country code, e.g. +33612345678
|
|
|
|
number = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
|
|
|
|
active = sa.Column(sa.Boolean, nullable=False, default=True)
|
|
|
|
|
2022-01-04 14:54:55 +01:00
|
|
|
# do not load this column
|
|
|
|
comment = deferred(sa.Column(sa.Text, nullable=True))
|
|
|
|
|
2021-12-02 16:50:26 +01:00
|
|
|
country = orm.relationship(PhoneCountry)
|
|
|
|
|
|
|
|
|
|
|
|
class PhoneReservation(Base, ModelMixin):
|
|
|
|
__tablename__ = "phone_reservation"
|
|
|
|
|
|
|
|
number_id = sa.Column(
|
|
|
|
sa.ForeignKey(PhoneNumber.id, ondelete="cascade"), nullable=False
|
|
|
|
)
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
|
|
|
|
number = orm.relationship(PhoneNumber)
|
|
|
|
|
|
|
|
start = sa.Column(ArrowType, nullable=False)
|
|
|
|
end = sa.Column(ArrowType, nullable=False)
|
|
|
|
|
|
|
|
|
|
|
|
class PhoneMessage(Base, ModelMixin):
|
|
|
|
__tablename__ = "phone_message"
|
|
|
|
|
|
|
|
number_id = sa.Column(
|
|
|
|
sa.ForeignKey(PhoneNumber.id, ondelete="cascade"), nullable=False
|
|
|
|
)
|
|
|
|
|
|
|
|
from_number = sa.Column(sa.String(128), nullable=False)
|
|
|
|
body = sa.Column(sa.Text)
|
|
|
|
|
|
|
|
number = orm.relationship(PhoneNumber)
|
|
|
|
|
|
|
|
|
2022-04-28 15:23:52 +02:00
|
|
|
# endregion
|
|
|
|
|
|
|
|
|
2022-03-10 16:13:31 +01:00
|
|
|
class AdminAuditLog(Base):
|
|
|
|
__tablename__ = "admin_audit_log"
|
|
|
|
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
|
|
|
created_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
2022-05-03 16:47:42 +02:00
|
|
|
admin_user_id = sa.Column(
|
|
|
|
sa.ForeignKey("users.id", ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
2022-03-10 16:13:31 +01:00
|
|
|
action = sa.Column(sa.Integer, nullable=False)
|
|
|
|
model = sa.Column(sa.Text, nullable=False)
|
2022-03-10 17:32:35 +01:00
|
|
|
model_id = sa.Column(sa.Integer, nullable=True)
|
2022-04-22 14:53:04 +02:00
|
|
|
data = sa.Column(sa.JSON, nullable=False)
|
2022-03-10 16:13:31 +01:00
|
|
|
|
2022-03-10 17:49:30 +01:00
|
|
|
admin = orm.relationship(User, foreign_keys=[admin_user_id])
|
|
|
|
|
2022-03-10 16:13:31 +01:00
|
|
|
@classmethod
|
|
|
|
def create(cls, **kw):
|
|
|
|
r = cls(**kw)
|
|
|
|
Session.add(r)
|
|
|
|
|
|
|
|
return r
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create_manual_upgrade(
|
|
|
|
cls, admin_user_id: int, upgrade_type: str, user_id: int, giveaway: bool
|
|
|
|
):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
action=AuditLogActionEnum.manual_upgrade.value,
|
2022-03-10 16:13:31 +01:00
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
|
|
|
data={
|
|
|
|
"upgrade_type": upgrade_type,
|
|
|
|
"giveaway": giveaway,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
2022-03-14 15:07:51 +01:00
|
|
|
def extend_trial(
|
|
|
|
cls, admin_user_id: int, user_id: int, trial_end: arrow.Arrow, extend_time: str
|
|
|
|
):
|
2022-03-10 16:13:31 +01:00
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
action=AuditLogActionEnum.extend_trial.value,
|
2022-03-10 16:13:31 +01:00
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
data={
|
|
|
|
"trial_end": trial_end.format(arrow.FORMAT_RFC3339),
|
|
|
|
"extend_time": extend_time,
|
|
|
|
},
|
2022-03-10 16:13:31 +01:00
|
|
|
)
|
|
|
|
|
2024-02-05 13:47:39 +01:00
|
|
|
@classmethod
|
|
|
|
def stop_trial(cls, admin_user_id: int, user_id: int):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
|
|
|
action=AuditLogActionEnum.stop_trial.value,
|
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
2024-07-18 14:48:18 +02:00
|
|
|
data={},
|
2024-02-05 13:47:39 +01:00
|
|
|
)
|
|
|
|
|
2022-03-10 16:13:31 +01:00
|
|
|
@classmethod
|
|
|
|
def disable_otp_fido(
|
|
|
|
cls, admin_user_id: int, user_id: int, had_otp: bool, had_fido: bool
|
|
|
|
):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
action=AuditLogActionEnum.disable_2fa.value,
|
2022-03-10 16:13:31 +01:00
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
|
|
|
data={"had_otp": had_otp, "had_fido": had_fido},
|
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def logged_as_user(cls, admin_user_id: int, user_id: int):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
action=AuditLogActionEnum.logged_as_user.value,
|
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
2022-04-22 14:53:04 +02:00
|
|
|
data={},
|
2022-03-14 15:07:51 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def extend_subscription(
|
|
|
|
cls,
|
|
|
|
admin_user_id: int,
|
|
|
|
user_id: int,
|
|
|
|
subscription_end: arrow.Arrow,
|
|
|
|
extend_time: str,
|
|
|
|
):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
|
|
|
action=AuditLogActionEnum.extend_subscription.value,
|
2022-03-10 16:13:31 +01:00
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
2022-03-14 15:07:51 +01:00
|
|
|
data={
|
|
|
|
"subscription_end": subscription_end.format(arrow.FORMAT_RFC3339),
|
|
|
|
"extend_time": extend_time,
|
|
|
|
},
|
2022-03-10 16:13:31 +01:00
|
|
|
)
|
|
|
|
|
2022-04-14 18:46:11 +02:00
|
|
|
@classmethod
|
2022-04-25 14:40:42 +02:00
|
|
|
def downloaded_provider_complaint(cls, admin_user_id: int, complaint_id: int):
|
2022-04-14 18:46:11 +02:00
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
2022-04-25 14:40:42 +02:00
|
|
|
action=AuditLogActionEnum.download_provider_complaint.value,
|
|
|
|
model="ProviderComplaint",
|
2022-04-14 18:46:11 +02:00
|
|
|
model_id=complaint_id,
|
|
|
|
data={},
|
|
|
|
)
|
|
|
|
|
2022-11-28 10:39:18 +01:00
|
|
|
@classmethod
|
|
|
|
def disable_user(cls, admin_user_id: int, user_id: int):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
|
|
|
action=AuditLogActionEnum.disable_user.value,
|
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
|
|
|
data={},
|
|
|
|
)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def enable_user(cls, admin_user_id: int, user_id: int):
|
|
|
|
cls.create(
|
|
|
|
admin_user_id=admin_user_id,
|
|
|
|
action=AuditLogActionEnum.enable_user.value,
|
|
|
|
model="User",
|
|
|
|
model_id=user_id,
|
|
|
|
data={},
|
|
|
|
)
|
|
|
|
|
2022-04-14 18:46:11 +02:00
|
|
|
|
2022-04-25 14:40:42 +02:00
|
|
|
class ProviderComplaintState(EnumE):
|
2022-04-14 18:46:11 +02:00
|
|
|
new = 0
|
|
|
|
reviewed = 1
|
2022-03-10 16:13:31 +01:00
|
|
|
|
2022-04-14 18:46:11 +02:00
|
|
|
|
2022-04-25 14:40:42 +02:00
|
|
|
class ProviderComplaint(Base, ModelMixin):
|
|
|
|
__tablename__ = "provider_complaint"
|
2022-04-14 18:46:11 +02:00
|
|
|
|
|
|
|
user_id = sa.Column(sa.ForeignKey("users.id"), nullable=False)
|
2022-05-03 14:15:50 +02:00
|
|
|
state = sa.Column(
|
|
|
|
sa.Integer, nullable=False, server_default=str(ProviderComplaintState.new.value)
|
|
|
|
)
|
2022-04-29 16:02:45 +02:00
|
|
|
phase = sa.Column(
|
|
|
|
sa.Integer, nullable=False, server_default=str(Phase.unknown.value)
|
|
|
|
)
|
2022-04-14 18:46:11 +02:00
|
|
|
# Point to the email that has been refused
|
|
|
|
refused_email_id = sa.Column(
|
|
|
|
sa.ForeignKey("refused_email.id", ondelete="cascade"), nullable=True
|
|
|
|
)
|
|
|
|
|
|
|
|
user = orm.relationship(User, foreign_keys=[user_id])
|
|
|
|
refused_email = orm.relationship(RefusedEmail, foreign_keys=[refused_email_id])
|
2022-03-14 09:33:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
class PartnerApiToken(Base, ModelMixin):
|
|
|
|
__tablename__ = "partner_api_token"
|
|
|
|
|
2022-06-02 11:24:04 +02:00
|
|
|
token = sa.Column(sa.String(50), unique=True, nullable=False, index=True)
|
2022-03-14 09:33:31 +01:00
|
|
|
partner_id = sa.Column(
|
|
|
|
sa.ForeignKey("partner.id", ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
|
|
|
expiration_time = sa.Column(ArrowType, unique=False, nullable=True)
|
|
|
|
|
2022-06-02 11:24:04 +02:00
|
|
|
@staticmethod
|
|
|
|
def generate(
|
|
|
|
partner_id: int, expiration_time: Optional[ArrowType]
|
|
|
|
) -> Tuple[PartnerApiToken, str]:
|
|
|
|
raw_token = random_string(32)
|
|
|
|
encoded = PartnerApiToken.hmac_token(raw_token)
|
|
|
|
instance = PartnerApiToken.create(
|
|
|
|
token=encoded, partner_id=partner_id, expiration_time=expiration_time
|
|
|
|
)
|
|
|
|
return instance, raw_token
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def hmac_token(token: str) -> str:
|
|
|
|
as_str = base64.b64encode(
|
|
|
|
hmac.new(
|
2022-06-30 11:40:01 +02:00
|
|
|
config.PARTNER_API_TOKEN_SECRET.encode("utf-8"),
|
2022-06-02 11:24:04 +02:00
|
|
|
token.encode("utf-8"),
|
|
|
|
hashlib.sha3_256,
|
|
|
|
).digest()
|
|
|
|
).decode("utf-8")
|
|
|
|
return as_str.rstrip("=")
|
|
|
|
|
2022-03-14 09:33:31 +01:00
|
|
|
|
|
|
|
class PartnerUser(Base, ModelMixin):
|
|
|
|
__tablename__ = "partner_user"
|
|
|
|
|
|
|
|
user_id = sa.Column(
|
|
|
|
sa.ForeignKey("users.id", ondelete="cascade"),
|
2022-06-09 10:19:49 +02:00
|
|
|
unique=True,
|
2022-03-14 09:33:31 +01:00
|
|
|
nullable=False,
|
|
|
|
index=True,
|
|
|
|
)
|
|
|
|
partner_id = sa.Column(
|
|
|
|
sa.ForeignKey("partner.id", ondelete="cascade"), nullable=False, index=True
|
|
|
|
)
|
2022-06-10 16:21:56 +02:00
|
|
|
external_user_id = sa.Column(sa.String(128), unique=False, nullable=False)
|
2022-03-14 09:33:31 +01:00
|
|
|
partner_email = sa.Column(sa.String(255), unique=False, nullable=True)
|
|
|
|
|
2022-06-09 10:19:49 +02:00
|
|
|
user = orm.relationship(User, foreign_keys=[user_id])
|
2022-06-20 14:34:20 +02:00
|
|
|
partner = orm.relationship(Partner, foreign_keys=[partner_id])
|
2022-06-09 10:19:49 +02:00
|
|
|
|
2022-03-14 09:33:31 +01:00
|
|
|
__table_args__ = (
|
2022-06-09 10:19:49 +02:00
|
|
|
sa.UniqueConstraint(
|
|
|
|
"partner_id", "external_user_id", name="uq_partner_id_external_user_id"
|
|
|
|
),
|
2022-03-14 09:33:31 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-06-09 10:19:49 +02:00
|
|
|
class PartnerSubscription(Base, ModelMixin):
|
|
|
|
"""
|
|
|
|
For users who have a subscription via a partner
|
|
|
|
"""
|
|
|
|
|
|
|
|
__tablename__ = "partner_subscription"
|
|
|
|
|
|
|
|
partner_user_id = sa.Column(
|
|
|
|
sa.ForeignKey(PartnerUser.id, ondelete="cascade"), nullable=False, unique=True
|
|
|
|
)
|
|
|
|
|
|
|
|
# when the partner subscription ends
|
2023-04-15 20:49:59 +02:00
|
|
|
end_at = sa.Column(ArrowType, nullable=False, index=True)
|
2022-06-09 10:19:49 +02:00
|
|
|
|
|
|
|
partner_user = orm.relationship(PartnerUser)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def find_by_user_id(cls, user_id: int) -> Optional[PartnerSubscription]:
|
|
|
|
res = (
|
|
|
|
Session.query(PartnerSubscription, PartnerUser)
|
|
|
|
.filter(
|
|
|
|
and_(
|
|
|
|
PartnerUser.user_id == user_id,
|
|
|
|
PartnerSubscription.partner_user_id == PartnerUser.id,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.first()
|
|
|
|
)
|
|
|
|
if res:
|
|
|
|
subscription, partner_user = res
|
|
|
|
return subscription
|
|
|
|
return None
|
|
|
|
|
|
|
|
def is_active(self):
|
|
|
|
return self.end_at > arrow.now().shift(days=-_PARTNER_SUBSCRIPTION_GRACE_DAYS)
|
|
|
|
|
|
|
|
|
2022-03-14 09:33:31 +01:00
|
|
|
# endregion
|
2022-07-22 11:24:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Newsletter(Base, ModelMixin):
|
|
|
|
__tablename__ = "newsletter"
|
2023-11-07 14:16:03 +01:00
|
|
|
subject = sa.Column(sa.String(), nullable=False, index=True)
|
2022-07-22 11:24:53 +02:00
|
|
|
|
|
|
|
html = sa.Column(sa.Text)
|
|
|
|
plain_text = sa.Column(sa.Text)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"<Newsletter {self.id} {self.subject}>"
|
|
|
|
|
|
|
|
|
|
|
|
class NewsletterUser(Base, ModelMixin):
|
|
|
|
"""This model keeps track of what newsletter is sent to what user"""
|
|
|
|
|
|
|
|
__tablename__ = "newsletter_user"
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=True)
|
|
|
|
newsletter_id = sa.Column(
|
|
|
|
sa.ForeignKey(Newsletter.id, ondelete="cascade"), nullable=True
|
|
|
|
)
|
|
|
|
# not use created_at here as it should only used for auditting purpose
|
|
|
|
sent_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
|
|
|
|
|
|
|
user = orm.relationship(User)
|
|
|
|
newsletter = orm.relationship(Newsletter)
|
2022-08-10 18:48:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
class ApiToCookieToken(Base, ModelMixin):
|
|
|
|
__tablename__ = "api_cookie_token"
|
|
|
|
code = sa.Column(sa.String(128), unique=True, nullable=False)
|
|
|
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
|
|
|
api_key_id = sa.Column(sa.ForeignKey(ApiKey.id, ondelete="cascade"), nullable=False)
|
|
|
|
|
|
|
|
user = orm.relationship(User)
|
|
|
|
api_key = orm.relationship(ApiKey)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create(cls, **kwargs):
|
|
|
|
code = secrets.token_urlsafe(32)
|
|
|
|
|
|
|
|
return super().create(code=code, **kwargs)
|
2024-05-23 10:27:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
class SyncEvent(Base, ModelMixin):
|
|
|
|
"""This model holds the events that need to be sent to the webhook"""
|
|
|
|
|
|
|
|
__tablename__ = "sync_event"
|
|
|
|
content = sa.Column(sa.LargeBinary, unique=False, nullable=False)
|
|
|
|
taken_time = sa.Column(
|
|
|
|
ArrowType, default=None, nullable=True, server_default=None, index=True
|
|
|
|
)
|
2024-07-23 16:11:16 +02:00
|
|
|
retry_count = sa.Column(sa.Integer, default=0, nullable=False, server_default="0")
|
2024-05-23 10:27:08 +02:00
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
sa.Index("ix_sync_event_created_at", "created_at"),
|
|
|
|
sa.Index("ix_sync_event_taken_time", "taken_time"),
|
|
|
|
)
|
|
|
|
|
|
|
|
def mark_as_taken(self) -> bool:
|
|
|
|
sql = """
|
|
|
|
UPDATE sync_event
|
|
|
|
SET taken_time = :taken_time
|
|
|
|
WHERE id = :sync_event_id
|
|
|
|
AND taken_time IS NULL
|
|
|
|
"""
|
|
|
|
args = {"taken_time": arrow.now().datetime, "sync_event_id": self.id}
|
2024-05-24 10:21:19 +02:00
|
|
|
|
2024-05-23 10:27:08 +02:00
|
|
|
res = Session.execute(sql, args)
|
2024-05-24 10:21:19 +02:00
|
|
|
Session.commit()
|
|
|
|
|
2024-05-23 10:27:08 +02:00
|
|
|
return res.rowcount > 0
|
|
|
|
|
|
|
|
@classmethod
|
2024-07-23 16:11:16 +02:00
|
|
|
def get_dead_letter(cls, older_than: Arrow, max_retries: int) -> [SyncEvent]:
|
2024-05-23 10:27:08 +02:00
|
|
|
return (
|
|
|
|
SyncEvent.filter(
|
|
|
|
(
|
|
|
|
(
|
|
|
|
SyncEvent.taken_time.isnot(None)
|
|
|
|
& (SyncEvent.taken_time < older_than)
|
|
|
|
)
|
|
|
|
| (
|
|
|
|
SyncEvent.taken_time.is_(None)
|
|
|
|
& (SyncEvent.created_at < older_than)
|
|
|
|
)
|
|
|
|
)
|
2024-07-23 16:11:16 +02:00
|
|
|
& (SyncEvent.retry_count < max_retries)
|
2024-05-23 10:27:08 +02:00
|
|
|
)
|
|
|
|
.order_by(SyncEvent.id)
|
|
|
|
.limit(100)
|
|
|
|
.all()
|
|
|
|
)
|
2024-10-14 12:45:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
class AliasAuditLog(Base, ModelMixin):
|
|
|
|
"""This model holds an audit log for all the actions performed to an alias"""
|
|
|
|
|
|
|
|
__tablename__ = "alias_audit_log"
|
|
|
|
|
|
|
|
user_id = sa.Column(sa.Integer, nullable=False)
|
|
|
|
alias_id = sa.Column(sa.Integer, nullable=False)
|
|
|
|
alias_email = sa.Column(sa.String(255), nullable=False)
|
|
|
|
action = sa.Column(sa.String(255), nullable=False)
|
|
|
|
message = sa.Column(sa.Text, default=None, nullable=True)
|
|
|
|
|
|
|
|
__table_args__ = (
|
|
|
|
sa.Index("ix_alias_audit_log_user_id", "user_id"),
|
|
|
|
sa.Index("ix_alias_audit_log_alias_id", "alias_id"),
|
|
|
|
sa.Index("ix_alias_audit_log_alias_email", "alias_email"),
|
|
|
|
)
|