Пример #1
0
def add_auth_controllers(app: Flask, config: Config, db: Database):

    oauth = OAuth(app, Cache())

    def handle_authorize(remote, token, user_info):
        sub = user_info['sub']
        email = user_info['email']
        user_info['providerName'] = remote.name
        session['user_info'] = user_info
        with db.session_scope() as conn:
            user = conn.query(User).filter(
                or_(User.sub == sub,
                    and_(User.email == email, User.email != None))).first()
            if not user:
                user = User(sub=sub, email=email)
                conn.add(user)
            user.email = email
            user.name = user_info['name']
            user.avatar = user_info['picture']
            conn.flush()
            session['user_id'] = user.id

        return redirect('/')

    for backend in backends:
        bp = create_flask_blueprint(backend, oauth, handle_authorize)
        app.register_blueprint(bp, url_prefix='/{}'.format(backend.OAUTH_NAME))

    @app.route('/logout')
    def logout():  # pylint: disable=unused-variable
        del session['user_info']
        del session['user_id']
        return redirect('/')
Пример #2
0
    def init_app(self, app):
        self.app = app

        app.auth_manager = self
        app.context_processor(_user_context_processor)
        app.context_processor(_user_roles_context_processor)

        if app.config.get('AUTH_METHOD') == 'google':
            app.config.setdefault('GOOGLE_ALLOWED_DOMAINS', [])

            from authlib.flask.client import OAuth
            self.oauth = OAuth(app)

            from loginpass import create_flask_blueprint
            from loginpass.google import Google
            from .google import handle_authorize

            google_bp = create_flask_blueprint(Google, self.oauth,
                                               handle_authorize)
            app.register_blueprint(google_bp, url_prefix='/auth/google')

            self.login_view = 'loginpass_google.login'
        elif app.config.get('AUTH_METHOD') == 'oidc':
            from authlib.flask.client import OAuth
            self.oauth = OAuth(app)

            from loginpass import create_flask_blueprint
            from .oidc import create_oidc_backend, handle_authorize

            backend = create_oidc_backend('oidc',
                                          app.config['OIDC_CLIENT_SECRETS'],
                                          app.config.get('OIDC_SCOPES'))
            oidc_bp = create_flask_blueprint(backend, self.oauth,
                                             handle_authorize)
            app.register_blueprint(oidc_bp, url_prefix='/auth/oidc')

            self.login_view = 'loginpass_oidc.login'
        else:
            from . import local_views
            app.register_blueprint(local_views.bp, url_prefix='/auth/local')

            self.login_view = 'auth_local.login'

        from . import views
        app.register_blueprint(views.bp, url_prefix='/auth')
Пример #3
0
def init_oauth(app):
    oauth2_client.init_app(app,
                           fetch_token=fetch_token,
                           update_token=update_token)
    backends = [loginpass.Google, loginpass.Facebook]
    loginpass_bp = loginpass.create_flask_blueprint(
            backends,
            oauth2_client,
            handle_authorize_oauth2)
    app.register_blueprint(loginpass_bp)
Пример #4
0
def init_oauth(app):
    oauth2_client.init_app(app,
                           fetch_token=fetch_token,
                           update_token=update_token)

    oauth2_client.register("engpsu")
    backends = [loginpass.Google]

    loginpass_bp = loginpass.create_flask_blueprint(backends, oauth2_client,
                                                    handle_authorize_google)
    app.register_blueprint(loginpass_bp)
Пример #5
0
def init_oauth(app):
    oauth2_client.init_app(app,
                           fetch_token=fetch_token,
                           update_token=update_token)

    oauth2_client.register('engpsu')
    # oauth2_client.register('google')

    google_bp = loginpass.create_flask_blueprint(loginpass.Google,
                                                 oauth2_client,
                                                 handle_authorize_google)
    app.register_blueprint(google_bp, url_prefix='/google')
Пример #6
0
def setup_authentication(app):
    oauth = OAuth(app)

    def handle_redirects(remote, token, user_info):
        if not 'hd' in user_info or user_info['hd'] != app.config['OAUTH_DOMAIN']:
            return redirect(url_for('page.login'))

        session['user'] = user_info
        return redirect(session.get('next', '/'))

    def ensure_user_is_authorized(app):
        if 'user' not in session and request.path not in ['/oauth/login', '/oauth/auth', '/login', '/healthcheck'] and not request.path.startswith('/static/'):
            session['next'] = request.url
            return redirect(url_for('page.login'))

    app.register_blueprint(
        create_flask_blueprint(Google, oauth, handle_redirects),
        url_prefix='/oauth')

    app.before_request(lambda: ensure_user_is_authorized(app))
Пример #7
0
def configure(app):
    """Configure OAuth and register auth blueprint."""
    def handle_authorize(remote, token, user_info):
        return _handle_authorize(app.bert_e, user_info)

    # configure web oauth
    if app.bert_e.settings.repository_host == 'github':
        backend = GitHub
        app.config['GITHUB_CLIENT_ID'] = app.config['CLIENT_ID']
        app.config['GITHUB_CLIENT_SECRET'] = app.config['CLIENT_SECRET']
    else:
        backend = Bitbucket
        app.config['BITBUCKET_CLIENT_ID'] = app.config['CLIENT_ID']
        app.config['BITBUCKET_CLIENT_SECRET'] = app.config['CLIENT_SECRET']

    oauth = OAuth(app)
    bp = create_flask_blueprint(backend, oauth, handle_authorize)
    app.register_blueprint(bp)

    # create additional path for token based authentication
    bp = Blueprint('auth', __name__)
    remote = register_to(backend, oauth, RemoteApp)

    @bp.route('/api/auth')
    def api_auth():
        access_token = request.args.get('access_token')
        if access_token:
            token = {'access_token': access_token, 'token_type': 'bearer'}
            user_info = remote.profile(token=token)
            return handle_authorize(remote, access_token, user_info)
        return unauthorized('Missing access token in request.')

    @bp.route('/logout')
    def logout():
        session.pop('user')
        session.pop('admin')
        return redirect(url_for('status page.display'))

    app.register_blueprint(bp)
Пример #8
0
def initialize_app(flask_app):
    # Register blueprints
    blueprint = Blueprint('api', __name__, url_prefix='/api')

    api.init_app(blueprint)

    # Add namespaces
    api.add_namespace(auth_ns)
    api.add_namespace(users_ns)
    api.add_namespace(resources_ns)

    flask_app.register_blueprint(blueprint)

    # Create blueprint for GitHub
    github_blueprint = create_flask_blueprint(GitHub, oauth,
                                              handle_oauth2_authorization)
    app.register_blueprint(github_blueprint, url_prefix='/github')

    # Configure OAuth2.0
    oauth.init_app(app)

    # Initialize database
    init_db()
Пример #9
0
    return (render_template('result.html'), 404)


@app.errorhandler(403)
def permission_denied(e):
    return redirect(url_for('login'))


@app.route('/webhook', methods=['POST'])
def webhook():
    app.logger.debug('Headers: %s', request.headers)
    app.logger.debug('Body: %s', request.get_data())
    return 'OK'


twitter_bp = create_flask_blueprint(Twitter, oauth, handle_authorize)
app.register_blueprint(twitter_bp, url_prefix='/twitter')
app.logger.setLevel(logging.DEBUG)
start_demo_db = False
if 'development' == app.config.get('ENV'):
    if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
        # This is the process that will be killed and restarted.
        # Can't do anything here, so just wait for the end.
        time.sleep(3600)
    start_demo_db = True
app.logger.info("App %s started. Env is %s" %
                (__name__, app.config.get('ENV')))
app.logger.debug("Logging at DEBUG level.")
game = Game(applog=app.logger, start_demo_db=start_demo_db)
app.logger.debug("Game connected.")
Пример #10
0
def create_app(settings_override=None, register_security_blueprint=True):
    """Returns the frontend application instance"""
    app = factory.create_app(__name__, __path__, settings_override)

    app.wsgi_app = WhiteNoise(app.wsgi_app,
                              root=app.static_folder,
                              prefix='static/')

    # Init assets
    assets.init_app(app)
    webpack.init_app(app)

    oauth.init_app(app)
    menu.init_app(app)
    gravatar.init_app(app)

    userdatastore = SQLAlchemyUserDatastore(db, models.User, models.Role)

    security_ctx = security.init_app(
        app,
        userdatastore,
        login_form=DeploymentLoginForm,
        register_blueprint=register_security_blueprint)

    @security_ctx.send_mail_task
    def delay_flask_security_mail(msg):
        send_email.delay(subject=msg.subject,
                         sender=msg.sender,
                         recipients=msg.recipients,
                         body=msg.body)

    # initialize the OpenAPI extension
    spec = APISpec(title='Apollo',
                   version='1.0.0',
                   openapi_version='3.0.2',
                   plugins=[MarshmallowPlugin()])
    app.config.update({'APISPEC_SPEC': spec})
    docs.init_app(app)

    csrf.init_app(app)
    init_admin(admin, app)

    monitor(app)

    # Register custom error handlers
    if not app.debug:
        for e in [500, 404, 403]:
            app.register_error_handler(e, handle_error)

    # register deployment selection middleware
    app.before_request(set_request_presets)

    # add Jinja2 filters
    app.jinja_env.filters.update(custom_filters)

    # Login and logout signal handlers
    user_logged_out.connect(clear_session)

    @identity_loaded.connect_via(app)
    def on_identity_loaded(sender, identity):
        if current_user.is_authenticated:
            user = current_user._get_current_object()
            needs = services.users.get_permissions_cache(user)

            for need in needs:
                identity.provides.add(need)

    @app.context_processor
    def inject_permissions():
        ga_key = app.config.get('GOOGLE_ANALYTICS_KEY')
        gtm_key = app.config.get('GOOGLE_TAG_MANAGER_KEY')
        return dict(perms=permissions, ga_key=ga_key, gtm_key=gtm_key)

    # clickjacking protection
    @app.after_request
    def frame_buster(response):
        response.headers['X-Frame-Options'] = app.config.get(
            'X_FRAME_OPTIONS', 'DENY')
        return response

    # content security policy
    @app.after_request
    def content_security_policy(response):
        response.headers['Content-Security-Policy'] = "default-src 'self' " + \
            "*.googlecode.com *.google-analytics.com fonts.gstatic.com fonts.googleapis.com " + \
            "*.googletagmanager.com " + \
            "cdn.heapanalytics.com heapanalytics.com " + \
            "'unsafe-inline' 'unsafe-eval' data:; img-src * data:"
        return response

    def handle_authorize(remote, token, user_info):
        if user_info and 'email' in user_info:
            user = models.User.query.filter_by(
                email=user_info['email']).first()
            if user:
                login_user(user)
                userdatastore.commit()
                return redirect(app.config.get('SECURITY_POST_LOGIN_VIEW'))

        return redirect(url_for_security('login'))

    @app.template_global()
    def modify_query(**values):
        args = request.args.copy()

        for k, v in values.items():
            if not v:
                _ = args.pop(k, None)
            else:
                args[k] = v

        return '{}?{}'.format(request.path, url_encode(args))

    facebook_bp = create_flask_blueprint(Facebook, oauth, handle_authorize)
    google_bp = create_flask_blueprint(Google, oauth, handle_authorize)

    if app.config.get('ENABLE_SOCIAL_LOGIN', False):
        app.register_blueprint(facebook_bp, url_prefix='/facebook')
        app.register_blueprint(google_bp, url_prefix='/google')

    return app
Пример #11
0
def register(app):
    """generates several flask blueprint for authentication (google,b2access) using authlib and loginpass


    registers these blueprints into Flask app instance
    and adds implementation of logout method + appropriate endpoint
    """
    oauth = OAuth(app)
    # registering flask blueprint with /b2access/login and /b2access/auth endpoints supporting oauth workflow
    b2accessbp = create_flask_blueprint(B2Access, oauth,
                                        handle_authorize_b2access)
    app.register_blueprint(b2accessbp, url_prefix='/b2access')

    # registering flask blueprint with /google/login and /google/auth endpoints supporting oauth workflow
    googlebp = create_flask_blueprint(Google, oauth, handle_authorize_google)
    app.register_blueprint(googlebp, url_prefix='/google')

    # registering flask endpoint to logout from any of the idp
    @app.route('/b2access/logout')
    @app.route('/google/logout')
    def logout():
        session.pop(AUTH_TOKEN_KEY, None)
        session.pop(AUTH_REFRESH_TOKEN, None)
        session.pop(USER_INFO, None)
        return redirect(BASE_URI, code=302)

    # register flask endpoint for getting user information
    @app.route('/userinfo')
    def index():
        if is_logged_in():
            user_info = get_user_info()
            return jsonify(user_info)
        #(token == 'test' and request.host == 'localhost:5000')
        # return test user info in case of local deployment
        if (request.headers.get('authorization') == 'Basic dGVzdDp0ZXN0'
                and request.host == 'localhost:5000'):
            users = app.data.driver.db['userprofile']
            a = users.find_one({'id': '0001'})
            ui = {"name": "Test", "id": "0001"}
            if a != None:
                #a['token'] = ui['token']
                ui = a
                ui['_id'] = str(ui['_id'])
            return jsonify(ui)
        return jsonify({"name": "Guest", "status": "not logged in."})

    def get_user_info():
        """"function to return user information stored in current session"""
        ui = session[USER_INFO]
        ui['token'] = session[AUTH_TOKEN_KEY]
        #if (ui['token'] == 'test' and request.host == 'localhost:5000'):
        #    ui['id']='0001'
        #check whether user exists in DB, and update fields accordingly
        users = app.data.driver.db['userprofile']
        a = users.find_one({'id': ui['id']})
        if a != None:
            #print(a)
            a['token'] = ui['token']
            ui = a
            ui['_id'] = str(ui['_id'])
        #print('get_user_info',ui['name'])
        return ui

    @app.route('/interface_main', methods=['POST'])
    def compatibility_redirect():
        #""" redirects old POST request with target id and source to GET request to new UI with params in url"""
        targetsource = request.form.get('subject_tofeed',
                                        '')  # source - direct link to file
        # request.form['recordurl_tofeed'] this is ignored in b2note v 1.0
        targetid = request.form.get('pid_tofeed', '')  # id - landingpage
        redirecturl = ('' if not BASE_URI else
                       BASE_URI) + '/#/b2note_home/id=' + str(
                           targetid) + '&source=' + str(targetsource)
        # /#/b2note_home/id=https:/someurl/sdf&source=http://someurl
        return redirect(redirecturl, code=303)
Пример #12
0
def create_app(app_name=PKG_NAME, **kwargs):
    """Start app.  Setup config profiles as needed."""
    app = Flask(__name__)
    # instance_relative_config=True, static_folder='./frontend/build', static_url_path='/')
    if app.config['ENV'] == "production":
        app.config.from_object("config.ProductionConfig")
    elif app.config['ENV'] == "testing":
        app.config.from_object("config.TestingConfig")
    else:
        app.config.from_object("config.DevelopmentConfig")

    # if kwargs.get('celery'):
    #     init_celery(kwargs.get('celery'), app)

    login.init_app(app)
    db.init_app(app)
    ma.init_app(app)
    cors.init_app(app,
                  resources={r"/api/v1/*": {
                      "origins": "http://*****:*****@legacydirectional.com',
    #         toaddrs=['*****@*****.**'], subject='Website Error',
    #         credentials=auth, secure=secure)
    #
    #     mail_handler.setLevel(logging.WARNING)
    #     mail_handler.setFormatter(email_request_formatter)
    #     app.logger.addHandler(mail_handler)

    # if not os.path.exists('logs'):
    #     os.mkdir('logs')

    # app.logger.setLevel(logging.INFO)
    # app.logger.info('Legacy startup')

    return app
Пример #13
0
    if not token or not user_info:
        raise RequestError(code=400,
                           message="Missing OAuth token or user info")

    # Find existing user, add to logged in user, or create a new user
    user = Connection.get_user_by_connection(
        site=remote.name, site_id=user_info['preferred_username'])
    if not user:
        user = get_authed_user()
        if not user:
            user = User()
        connection = Connection(
            userid=user.id,
            site=remote.name,
            site_id=user_info['preferred_username'],
            site_username=user_info['preferred_username'],
        )
        user.connections.append(connection)
        db.session.add(user)
        db.session.add(connection)
        db.session.commit()

    # Set them as logged in in the session
    session['user_id'] = user.id
    redirect_url = frontend_url('/user/me')
    return redirect(redirect_url)


github_blueprint = create_flask_blueprint(GitHub, oauth, handle_authorize)
gitlab_blueprint = create_flask_blueprint(Gitlab, oauth, handle_authorize)
Пример #14
0
    print("Found and using privileged token (eg, for account signup)")
    priv_api = auth_api(Config.FATCAT_API_AUTH_TOKEN)
else:
    print("No privileged token found")
    priv_api = None

# TODO: refactor integration so this doesn't always need to be definied. If
# key/secret are empty, library will not init; if init is skipped, get
# undefined errors elsewhere.
mwoauth = MWOAuth(
    consumer_key=Config.WIKIPEDIA_CLIENT_ID or "dummy",
    consumer_secret=Config.WIKIPEDIA_CLIENT_SECRET or "dummy",
    default_return_to='wp_oauth_finish_login')
mwoauth.handshaker.user_agent = "fatcat.wiki;python_web_interface"
app.register_blueprint(mwoauth.bp, url_prefix='/auth/wikipedia')

from fatcat_web import routes, editing_routes, auth, cors, forms

# TODO: blocking on ORCID support in loginpass
if Config.ORCID_CLIENT_ID:
    orcid_bp = create_flask_blueprint(ORCiD, oauth, auth.handle_oauth)
    app.register_blueprint(orcid_bp, url_prefix='/auth/orcid')

if Config.GITLAB_CLIENT_ID:
    gitlab_bp = create_flask_blueprint(Gitlab, oauth, auth.handle_oauth)
    app.register_blueprint(gitlab_bp, url_prefix='/auth/gitlab')

if Config.GITHUB_CLIENT_ID:
    github_bp = create_flask_blueprint(GitHub, oauth, auth.handle_oauth)
    app.register_blueprint(github_bp, url_prefix='/auth/github')
Пример #15
0
def load(app):
    url_prefix = "/oidc"
    oidc_login_backend = app.config.setdefault('OIDC_LOGIN_BACKEND',
                                               os.environ.get('OIDC_LOGIN_BACKEND', None))
    create_missing_user = app.config.setdefault('OIDC_CREATE_MISSING_USER',
                                                os.environ.get('OIDC_CREATE_MISSING_USER', False))

    def get_user(email):
        user = Users.query.filter_by(email=email).first()
        if user is not None:
            log('logins', "[{date}] {ip} - " +
                email + " - OIDC bridged user found")
            return user

    def create_user(email, name):
        log('logins', "[{date}] {ip} - " + email +
            " - No OIDC bridged user found, creating user")
        user = Users(email=email, name=name.strip(), verified=True)
        db.session.add(user)
        db.session.commit()
        return user
    
    def get_or_create_user(email, name):
        user = get_user(email)
        if user is not None:
            return user
        if create_missing_user:
            return create_user(email, name)
        else:
            log('logins', "[{date}] {ip} - " + email +
                " - No OIDC bridged user found and not configured to create missing users")
            return None

    def handle_authorize(remote, token, user_info):

        with app.app_context():
            user = get_or_create_user(
                email=user_info["email"],
                name=user_info["name"])

            if user is not None:
                session.regenerate()
                login_user(user)
                log("logins", "[{date}] {ip} - " + user.name + " logged in")
                db.session.close()
                return redirect(url_for("challenges.listing"))

        return redirect('/')


    def create_azure_backend(name, tenant='common'):

        metadata_url = f'https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration'

        class AzureAD(object):
            NAME = name
            OAUTH_CONFIG = {
                'api_base_url': 'https://graph.microsoft.com/',
                'server_metadata_url': metadata_url,
                'client_kwargs': {'scope': 'openid email profile'},
            }

            def load_server_metadata(self):
                metadata = super(AzureAD, self).load_server_metadata()
                # fix issuer value
                issuer = metadata['issuer']
                issuer = issuer.replace('{tenantid}', tenant)
                metadata['issuer'] = issuer
                return metadata

        return AzureAD

    backend = None

    if oidc_login_backend == 'azure':
        app.config.setdefault('AZURE_TENANT_ID',
                              os.environ.get('AZURE_TENANT_ID', 'common'))
        app.config.setdefault('AZURE_CLIENT_ID',
                              os.environ.get('AZURE_CLIENT_ID', 'missing_client_id'))
        app.config.setdefault('AZURE_CLIENT_SECRET',
                              os.environ.get('AZURE_CLIENT_SECRET', 'missing_client_secret'))
        backend = create_azure_backend('azure', app.config['AZURE_TENANT_ID'])
    else:
        print('** Skip loading CTFd-OIDC because of the unknown or unsupported OIDC backend **')
        return

    oauth = OAuth(app)

    bp = create_flask_blueprint([backend], oauth, handle_authorize)
    app.register_blueprint(bp, url_prefix=url_prefix)

    ###############################
    # Application Reconfiguration #
    ###############################
    # ('', 204) is "No Content" code
    set_config('registration_visibility', False)
    app.view_functions['auth.login'] = lambda: redirect(
        url_prefix + "/login/" + oidc_login_backend)
    app.view_functions['auth.register'] = lambda: ('', 204)
    app.view_functions['auth.reset_password'] = lambda: ('', 204)
    app.view_functions['auth.confirm'] = lambda: ('', 204)     
Пример #16
0
def init(app,
         db,
         config,
         base_prefix='/auth',
         root_uri='/',
         providers=['google', 'facebook', 'github'],
         smtp=None,
         fix_ssl=True):
    """
    Initalize framework

    Args:
        app: Flask app
        db: pyaltt2.db.Database object
        config: configuration dict
        base_prefix: base prefix for auth urls
        root_uri: default next uri
        providers: oauth2 providers list
        smtp: pyaltt2.mail.SMTP object, required if email confirmations are
        used
        fix_ssl: force SSL everywhere (True by default)
    """

    if not app.config.get('SECRET_KEY'):
        app.config['SECRET_KEY'] = gen_random_str()

    _d.x_prefix, _d.dot_prefix = _format_prefix(base_prefix)
    _d.db = db.clone(rq_func=rq)
    _d.kv = KVStorage(db=db, table_name='webauth_kv')
    _d.root_uri = root_uri
    _d.smtp = smtp

    if fix_ssl:
        from werkzeug.middleware.proxy_fix import ProxyFix
        app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1)

    def init_db():
        from sqlalchemy import (MetaData, Table, Column, BigInteger, VARCHAR,
                                JSON, CHAR, DateTime, ForeignKey, Index,
                                Boolean, Numeric)
        meta = MetaData()
        user = Table(
            'webauth_user', meta,
            Column('id', BigInteger(), primary_key=True, autoincrement=True),
            Column('email', VARCHAR(255), nullable=True, unique=True),
            Column('password', CHAR(64), nullable=True),
            Column('api_key', CHAR(32), nullable=True, unique=True),
            Index('webauth_user_api_key', 'api_key'),
            Column('d_created', DateTime(timezone=True), nullable=False),
            Column('d_active', DateTime(timezone=True), nullable=True),
            Column('confirmed', Boolean, nullable=False, server_default='0'),
            Column('otp', Numeric(1, 0), nullable=False, server_default='0'),
            Column('otp_secret', CHAR(16), nullable=True))
        user_auth = Table(
            f'webauth_user_auth', meta,
            Column('id', BigInteger(), primary_key=True, autoincrement=True),
            Column('user_id',
                   BigInteger(),
                   ForeignKey('webauth_user.id', ondelete='CASCADE'),
                   nullable=False),
            Index('webauth_user_auth_user_id', 'user_id'),
            Column('provider', VARCHAR(15), nullable=False),
            Column('sub', VARCHAR(255), nullable=False),
            Column('name', VARCHAR(255), nullable=True),
            Index('webauth_user_auth_sub_provider',
                  'sub',
                  'provider',
                  unique=True))
        user_log = Table(
            f'webauth_user_log', meta,
            Column('id', BigInteger(), primary_key=True, autoincrement=True),
            Column('user_id', BigInteger(), nullable=False),
            Index('webauth_user_log_user_id', 'user_id'),
            Column('d', DateTime(timezone=True), nullable=False),
            Column('event', VARCHAR(1024), nullable=False),
            Column('ip', VARCHAR(45), nullable=False))
        meta.create_all(db.connect())

    def handle_authorize(remote, token, user_info):
        if user_info:
            try:
                provider = remote if isinstance(remote, str) else remote.name
                user_id = _handle_user_auth(user_info, provider=provider)
                touch(user_id)
                session[f'{_d.x_prefix}user_id'] = user_id
                session[f'{_d.x_prefix}user_picture'] = user_info.picture
                session[f'{_d.x_prefix}user_name'] = _get_oauth_user_name(
                    user_info, provider)
                session[f'{_d.x_prefix}user_confirmed'] = True
                _call_handler('account.login', user_id=user_id)
                _log_user_event(f'account.login:{provider}')
                return redirect(_next_uri())
            except ResourceAlreadyExists:
                response = _call_handler('exception.provider_exists')
                return response if response else Response(
                    'oauth provider is already ' +
                    'registered for another account',
                    status=409)
            except AccessDenied:
                response = _call_handler('exception.registration_denied')
                return response if response else Response(
                    'account registration is disabled', status=403)
            # session.permanent = True
        else:
            response = _call_handler('exception.provider_failed')
            return response if response else Response('forbidden', status=403)

    def google_login():
        redirect_uri = url_for(f'{_d.dot_prefix}google.auth', _external=True)
        return oauth.google.authorize_redirect(redirect_uri)

    def google_auth():
        token = oauth.google.authorize_access_token()
        user_info = oauth.google.parse_id_token(token)
        return handle_authorize('google', token, user_info)

    for k in config:
        app.config[k.upper().replace('-', '_')] = config_value(config=config,
                                                               config_path=k)
    oauth = OAuth(app)
    app.add_url_rule(f'{base_prefix}/logout',
                     f'{_d.dot_prefix}.logout',
                     logout,
                     methods=['GET'])
    app.add_url_rule(f'{base_prefix}/confirm/<key>',
                     f'{_d.dot_prefix}confirm',
                     handle_confirm,
                     methods=['GET'])
    for p in providers:
        if p == 'google':
            oauth.register(
                'google',
                server_metadata_url=
                'https://accounts.google.com/.well-known/openid-configuration',
                client_kwargs={'scope': 'openid profile'},
            )
            app.add_url_rule(f'{base_prefix}/google/login',
                             f'{_d.dot_prefix}google.login',
                             google_login,
                             methods=['GET'])
            app.add_url_rule(f'{base_prefix}/google/auth',
                             f'{_d.dot_prefix}google.auth',
                             google_auth,
                             methods=['GET'])
        else:
            blueprint = loginpass.create_flask_blueprint(
                _provider_mod[p], oauth, handle_authorize)
            app.register_blueprint(blueprint, url_prefix=f'{base_prefix}/{p}')
    init_db()
    return
Пример #17
0
# Grabs sentry config from SENTRY_DSN environment variable
sentry = Sentry(app)

conf = fatcat_client.Configuration()
conf.host = Config.FATCAT_API_HOST
api = fatcat_client.DefaultApi(fatcat_client.ApiClient(conf))

# remove most jinja2 template whitespace
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True

def auth_api(token):
    conf = fatcat_client.Configuration()
    conf.api_key["Authorization"] = token
    conf.api_key_prefix["Authorization"] = "Bearer"
    conf.host = Config.FATCAT_API_HOST
    return fatcat_client.DefaultApi(fatcat_client.ApiClient(conf))

if Config.FATCAT_API_AUTH_TOKEN:
    print("Found and using privileged token (eg, for account signup)")
    priv_api = auth_api(Config.FATCAT_API_AUTH_TOKEN)
else:
    print("No privileged token found")
    priv_api = None

from fatcat_web import routes, auth, cors

gitlab_bp = create_flask_blueprint(Gitlab, oauth, auth.handle_oauth)
app.register_blueprint(gitlab_bp, url_prefix='/auth/gitlab')
Пример #18
0
    session[token_session_key] = token
    return token


oauth = OAuth(app, fetch_token=fetch_token, update_token=update_token)


# Define gitlab login handler
def handle_authorize(remote, token, user_info):
    session['user'] = user_info
    session['token'] = token
    return redirect(url_for('facts'))


gitlab_backend = create_gitlab_backend(OAUTH_APP_NAME, GITLAB_HOST)
bp = create_flask_blueprint([gitlab_backend], oauth, handle_authorize)
app.register_blueprint(bp, url_prefix='')


@app.route('/', methods=['GET', 'POST'])
def facts():
    user = session.get('user', None)
    if user is None:
        return render_template('login.html')
        return redirect('/login/gitlab')
    user['id'] = int(user['sub'])

    if not session.get('project') or not session.get(
            'web_url') or not session.get('added_user'):
        init_project(user)
Пример #19
0
            </head>
            <body>
                <script>
                    window.opener.postMessage(
                        "{token}",
                        "{app.config['FRONTEND_URL']}"
                    );
                    window.close();
                </script>
            </body>
        </html>
    '''


oauth = OAuth(app)
bp = create_flask_blueprint([Discord], oauth, handle_authorize)
app.register_blueprint(bp, url_prefix='')


@app.teardown_appcontext
def shutdown_session(exception=None):
    db.remove()


@app.before_first_request
def start_db():
    calcStats()


def calcStats():
    global solveCounts
Пример #20
0
        User.create(remote.name, external_id, name, email, profile_pic,
                    request.headers.get('CF-IPCountry') or 'XX')
    user = User.get_user_from_email(email)
    if user.identity_provider != remote.name:
        return redirect("/409")

    # TODO updte last_login date
    login_user(user)

    return redirect("/gallery")


Hydra = create_hydra_backend("hydra", FOTRINO_HYDRA_HOST)

bp = create_flask_blueprint([
    Facebook, Google, GitHub, Reddit, Instagram, Gitlab, LinkedIn,
    StackOverflow, Hydra
], oauth, handle_authorize)
app.register_blueprint(bp, url_prefix='/api/account')

# Account Routes ##############################################################
###############################################################################


@app.route("/api/account/providers", methods=['GET'])
def get_oauth_providers():
    return json.dumps(FOTRINO_OAUTH_PROVIDERS)


@app.route("/api/account/profile", methods=['GET'])
@login_required
def get_profile():
Пример #21
0
def init_webapp(config, test=False):
    """Initialize the web application.

    Initializes and configures the Flask web application. Call this method to
    make the web application and respective database engine usable.

    If initialized with `test=True` the application will use an in-memory
    SQLite database, and should be used for unit testing, but not much else.

    """

    # Make app work with proxies (like nginx) that set proxy headers.
    app.wsgi_app = ProxyFix(app.wsgi_app)

    # logging.getLogger('flask_cors').level = logging.DEBUG

    # Note, this url namespace also exists for the Flask-Restless extension and
    # is where CRUD interfaces live, so be careful not to collide with model
    # names here. We could change this, but it's nice to have API live in the
    # same url namespace.
    app.register_blueprint(api, url_prefix='/api')

    # Initialize Flask configuration
    if test:
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
    else:
        app.config['SQLALCHEMY_DATABASE_URI'] = config['webapp'][
            'database_uri']

    # FIXME: Port these over to configobj.
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'abc123')
    app.config['SECURITY_TOKEN_MAX_AGE'] = 60
    app.config['SECURITY_TOKEN_AUTHENTICATION_HEADER'] = 'Auth-Token'
    app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
    app.config['SECURITY_PASSWORD_SALT'] = os.environ.get('SALT', 'salt123')
    app.config['SECURITY_REGISTERABLE'] = True
    app.config['SECURITY_CONFIRMABLE'] = False
    app.config['SECURITY_SEND_REGISTER_EMAIL'] = False

    # This thing is a supreme PIA with API, and because we're using token based
    # authentication.
    app.config['WTF_CSRF_ENABLED'] = False

    # Initialize Flask-CORS
    CORS(app, supports_credentials=True)
    # CORS(app, supports_credentials=True, resources={r"/*": {"origins": "*"}})

    # Initialize Flask-Bootstrap
    Bootstrap(app)

    # Initialize Flask-Security
    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    Security(app, user_datastore)

    app.config['GOOGLE_CLIENT_ID'] = os.environ.get('GOOGLE_CLIENT_ID',
                                                    'abc123')
    app.config['GOOGLE_CLIENT_SECRET'] = os.environ.get(
        'GOOGLE_CLIENT_SECRET', 'password')
    app.config[
        'GOOGLE_REFRESH_TOKEN_URL'] = 'https://www.googleapis.com/oauth2/v4/token'
    app.config['GOOGLE_CLIENT_KWARGS'] = dict(scope=' '.join([
        'openid',
        'https://www.googleapis.com/auth/userinfo.profile',
        'https://www.googleapis.com/auth/calendar.readonly',
    ]))

    # Initialize Authlib.
    oauth = OAuth()
    oauth.init_app(app,
                   fetch_token=authlib_fetch_token,
                   update_token=authlib_update_token)
    google_blueprint = create_flask_blueprint(Google, oauth,
                                              authlib_handle_authorize)
    app.register_blueprint(google_blueprint, url_prefix='/google')
    # Save the oauth object in the app so handlers can use it to build clients.
    app.oauth = oauth

    # Initialize Flask-SQLAlchemy
    db.app = app
    db.init_app(app)
    # NOTE: You don't want to use this if you're using alembic, since alembic
    # is now in charge of creating/upgrading/downgrading your database. If you
    # choose to not use alembic, you can add this line here.
    # db.create_all()

    # Initialize Flask-Restless
    manager = APIManager(
        app,
        flask_sqlalchemy_db=db,
        preprocessors=dict(GET_MANY=[restless_api_auth_func]),
    )
    # manager.create_api(TableName methods=['GET', 'POST', 'OPTIONS'])
    return app
 def __init__(self, register, libraries, settings):
     print("Start OAuth 2.0 Server")
     app = Flask(__name__)
     oauth = OAuth(app)
     github_bp = create_flask_blueprint(GitHub, oauth, self.handle_authorize)
     app.register_blueprint(github_bp, url_prefix='/github')
Пример #23
0
    # If a 'next' URL is provided, then store it into the session
    # to redirect the user after the authorization is complete
    if 'next_url' in request.args:
        session['next_url'] = request.args.get('next_url')
    return render_template('index.html')


def handle_authorize(remote, token, user_info):
    refresh_token_value = token['refresh_token']
    encrypted_value = encrypt(settings.ENCRYPTION_REFRESH_TOKEN_CRYPTO_KEY,
                              refresh_token_value)

    gcp_user = user_info['email']
    validate_domain(gcp_user)

    # Save the refresh token
    refresh_token = RefreshToken(id=gcp_user, value=encrypted_value)
    refresh_token.save()

    # Retrieve next URL from the session, if any
    next_url = session.pop('next_url', None)

    return render_template('success.html', next_url=next_url)


oauth = OAuth(app)
bp = create_flask_blueprint(Google, oauth, handle_authorize)
app.register_blueprint(bp, url_prefix='/google')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
Пример #24
0
    return render_template('public/home.html', form=form)


def handle_authorize(remote, token, user_info):
    email = user_info['email']
    user = db.session.query(User).filter_by(email=email).first()
    if not user:
        User.create(username=user_info['name'],
                    email=user_info['email'],
                    active=True)
    else:
        return 'User exists'
    return redirect(url_for('public.home'))


google_bp = create_flask_blueprint(Google, oauth, handle_authorize)
github_bp = create_flask_blueprint(GitHub, oauth, handle_authorize)


@blueprint.route('/logout/')
@login_required
def logout():
    """Logout."""
    logout_user()
    flash('You are logged out.', 'info')
    return redirect(url_for('public.home'))


@blueprint.route('/register/', methods=['GET', 'POST'])
def register():
    """Register new user."""
Пример #25
0
    # Bitbucket, Spotify, Strava
)

# app imports
from mjserver import app

#%% oauth stuff


OAUTH_BACKENDS = [ Discord, Google,
    # Twitter, Facebook, GitHub, Dropbox,
    # Reddit, Gitlab, Slack, StackOverflow,
    # Bitbucket, Strava, Spotify
]

@app.route('/hid/')
def oauth_login_list():
    tpl = '<li><a href="/{}/login">{}</a></li>'
    lis = [tpl.format(b.OAUTH_NAME, b.OAUTH_NAME) for b in OAUTH_BACKENDS]
    return '<ul>{}</ul>'.format(''.join(lis))

def handle_authorize(remote, token, user_info):
    # type(remote) == RemoteApp # str(token)
    return str(user_info)

oauth = OAuth(app)

for backend in OAUTH_BACKENDS:
    bp = create_flask_blueprint(backend, oauth, handle_authorize)
    app.register_blueprint(bp, url_prefix='/{}'.format(backend.OAUTH_NAME))
Пример #26
0
    def create_flask_application(self):
        application = Flask(__name__)
        gzip = Gzip(application)
        application.log = {}
        application.killurl = str(uuid.uuid4())
        application.jinja_env.add_extension('jinja2.ext.do')

        application.config.update(
            SESSION_TYPE='filesystem',
            PERMANENT_SESSION_LIFETIME=60*15, # 15 min
            SECRET_KEY=self.secret_key,
            GITHUB_CLIENT_ID=self.client_id,
            GITHUB_CLIENT_SECRET=self.client_secret,
            GITHUB_CLIENT_KWARGS = {
                'scope': 'repo'
            }
        )
        Session(application)
        oauth = OAuth(application)
        github_bp = create_flask_blueprint(GitHub, oauth, handle_authorize)
        application.register_blueprint(github_bp, url_prefix='/github')

        @application.template_filter('remove_terms', )
        def remove_terms(content, repository_configuration, word_boundaries=True, whole_urls=True):
            """
            remove the blacklisted terms from the content
            :param content: the content to anonymize
            :param repository_configuration: the configuration of the repository
            :return: the anonymized content
            """
            repo = repository_configuration['repository']
            if repo[-1] == '/':
                repo = repo[0:-1]
            content = re.compile("%s/blob/master" % repo, re.IGNORECASE).sub(
                "%s/repository/%s" % (self.public_url, repository_configuration["id"]), content)
            content = re.compile(repo, re.IGNORECASE).sub("%s/repository/%s" % (self.public_url, repository_configuration["id"]), content)
            for term in repository_configuration['terms']:
                if word_boundaries:
                    regex = re.compile(r'\b%s\b' % term, re.IGNORECASE)
                else:
                    regex = re.compile(term, re.IGNORECASE)

                if whole_urls:
                    def sub_url(m):
                        if regex.search(m.group(0)):
                            return 'XXX'
                        return m.group(0)

                    url_regex = re.compile('\\b((https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]\\b')
                    content = url_regex.sub(sub_url, content)

                content = regex.sub("XXX", content)
            return content

        @application.template_filter('file_render', )
        def file_render(file, repository_configuration):
            """
            produce the html representation of a file
            :param file: the file to display
            :param repository_configuration: the configuration of the repository
            :return: the html representation of the file
            """
            if type(file) == github.Commit.Commit:
                return Markup(remove_terms(render_template('patch.html', patch=file), repository_configuration))
            if file.type == 'dir':
                return ""
            if file.size > 1000000:
                return Markup("The file %s is too big to be anonymized (beyond 1MB, Github limit)" % (file.name))
            if ".md" in file.name or file.name == file.name.upper() or "changelog" == file.name.lower():
                gh = self.github
                if 'token' in repository_configuration and repository_configuration['token'] is not None:
                    gh = github.Github(repository_configuration['token'])
                return Markup("<div class='markdown-body'>%s</div>" % remove_terms(
                    gh.render_markdown(file.decoded_content.decode('utf-8')),
                    repository_configuration))
            if ".jpg" in file.name or ".png" in file.name or ".png" in file.name or ".gif" in file.name:
                index = file.name.index('.')
                file_extension = file.name[index + 1:]
                return Markup("<img src='data:image/%s;base64, %s' alt='%s'>" % (file_extension, file.content, file.name))
            if istext(file.decoded_content):
                return Markup("<pre><code>{}</code></pre>")\
                           .format(Markup.escape(remove_terms(file.decoded_content.decode("utf-8"), repository_configuration)))
            return Markup("<b>%s has an unknown extension, we are unable to anonymize it (known extensions md/txt/json/java/...)</b>" % (file.name))

        @application.route('/' + application.killurl, methods=['POST'])
        def seriouslykill():
            func = request.environ.get('werkzeug.server.shutdown')
            func()
            return "Shutting down..."

        def get_element_from_path(g_repo, g_commit, path):
            """
            get a github element from its path
            :param g_repo: the github repository
            :param path: the path of the element
            :return: the element
            """
            if path == '':
                return g_repo.get_contents('', g_commit.sha), None
            current_element = os.path.basename(path)
            folder_content = g_repo.get_contents(quote(os.path.dirname(path)), g_commit.sha)
            for file in folder_content:
                if file.name == current_element:
                    return file, folder_content
            return None, folder_content

        @application.route('/myrepo', methods=['GET'])
        def myrepo():
            user = session.get('user', None)
            if user is None or 'token' not in user or user['token'] is None:
                return redirect('github/login')
            g = github.Github(user['token']['access_token'])
            repos = g.get_user().get_repos(sort="full_name")
            for repo in repos:
                repo.uuid = str(uuid.uuid4())
            return render_template('newrepo.html', repos=repos)
            

        @application.route('/repository/<id>/commit/<sha>', methods=['GET'])
        def commit(id, sha):
            """
            display anonymously a commit from the repository
            :param id: the repository id
            :param sha: the commit id
            """
            config_path = self.config_dir + "/" + str(id) + "/config.json"
            if not os.path.exists(config_path):
                return render_template('404.html'), 404
            with open(config_path) as f:
                data = json.load(f, object_hook=json_util.object_hook)
                (username, repo, branch) = clean_github_repository(data['repository'])
                gh = self.github
                if 'token' in data:
                    gh = github.Github(data['token'])
                g_repo = gh.get_repo("%s/%s" % (username, repo))
                commit = g_repo.get_commit(sha)
                return render_template('repo.html',
                                   repository=data,
                                   current_repository=id,
                                   current_file=commit,
                                   files=[],
                                   path=[])

        def is_up_to_date(repository_config, g_commit):
            """
            check is the cache is up to date
            :param repository_config: the repository configuration
            :param g_commit: the Github commit
            :return: True if the cache is up to date
            """
            commit_date = datetime.strptime(g_commit.last_modified, "%a, %d %b %Y %H:%M:%S %Z")
            return 'pushed_at' in repository_config and commit_date.strftime("%s") == repository_config["pushed_at"]

        def get_type_content(file_name, path, repository_configuration, g_repo, is_website):
            """
            Get the content type of a file from its extension
            :param file_name: the filename
            :param path: the path of the file
            :param repository_configuration: the repository configuration
            :param g_repo: the Github repository
            :return: the content type
            """
            if is_website:
                content_type = 'text/plain; charset=utf-8'
                if ".html" in file_name:
                    content_type = 'text/html; charset=utf-8'
                if ".md" in file_name or file_name == file_name.upper():
                    content_type = 'text/html; charset=utf-8'
                if ".jpg" in file_name \
                        or ".png" in file_name \
                        or ".gif" in file_name:
                    content_type = 'image/jpeg'
                    if ".png" in file_name:
                        content_type = 'image/png'
                    elif ".gif" in file_name:
                        content_type = 'image/gif'
                if ".txt" in file_name \
                        or ".log" in file_name \
                        or ".csv" in file_name \
                        or ".xml" in file_name \
                        or ".json" in file_name \
                        or ".java" in file_name \
                        or ".py" in file_name \
                        or ".lua" in file_name \
                        or ".js" in file_name:
                    content_type = 'text/plain; charset=utf-8'
                    if ".xml" in file_name:
                        content_type = 'application/xml; charset=utf-8'
                    elif ".json" in file_name:
                        content_type = 'application/json; charset=utf-8'
                    elif ".js" in file_name:
                        content_type = 'application/javascript; charset=utf-8'
                if ".css" in file_name:
                    content_type = 'text/css; charset=utf-8'
                return content_type
            return 'text/html; charset=utf-8'

        def get_content(current_file, files, path, repository_config, g_repo):
            """
            get the content if the page
            :param current_file: the current file
            :param files: the list of file of the current directory
            :param path: the accessed path
            :param repository_config: the repository configuration
            :param g_repo: the Github repository
            :return: the content of the page
            """
            cache_path = os.path.join(self.config_dir, repository_config['id'], "cache")
            file_path = path
            if current_file is not None:
                if current_file.type == 'dir':
                    file_path = os.path.join(current_file.path, "index.html")
                else:
                    file_path = current_file.path
            cached_file_path = os.path.join(cache_path, file_path)
            content_type = get_type_content(path, path, repository_config, g_repo, False).replace("; charset=utf-8", "")
            if os.path.exists(cached_file_path):
                return send_from_directory(os.path.dirname(cached_file_path), os.path.basename(cached_file_path),
                                           mimetype=content_type)
            content = ''
            if current_file.type != 'dir' and is_website(path, repository_config, g_repo):
                if current_file.size > 1000000:
                    blob = g_repo.get_git_blob(current_file.sha)
                    if blob.encoding == 'base64':
                        content = base64.b64decode(blob.content).decode('utf-8')
                    else:
                        content = blob.content.decode('utf-8')
                else:
                    content = current_file.decoded_content.decode('utf-8')
                if "text" in content_type:
                    content = remove_terms(content, repository_config)
                if ".md" in current_file.name:
                    gh = self.github
                    if 'token' in repository_config:
                        gh = github.Github(repository_config['token'])
                    content = remove_terms(gh.render_markdown(content), repository_config)
            else:
                tree = files 
                if type(tree) != list:
                    tree = files.tree
                content = render_template('repo.html',
                                       repository=repository_config,
                                       current_repository=repository_config['id'],
                                       current_file=current_file,
                                       files=tree,
                                       path_directory=path if type(
                                           current_file) is not github.ContentFile.ContentFile or current_file.type == 'dir' else os.path.dirname(
                                           current_file.path),
                                       path=path.split("/") if path != '' else [])
            content_cache_path = cached_file_path
            if not os.path.exists(os.path.dirname(content_cache_path)):
                os.makedirs(os.path.dirname(content_cache_path))
            with open(content_cache_path, 'w') as f:
                if type(content) == str:
                    f.write(content)
                else:
                    f.write(content.encode('utf8'))
            return content

        def is_website(path, repository_config, g_repo):
            """
            Check if the current request is a request to a GitHub pages
            :param path: the current path
            :param repository_config: the repository configuration
            :param g_repo: the Github repository
            :return: True if the current path is a website
            """
            return path[:4] == "docs"

        def is_default_file(f):
            default_name = ["readme", "index"]
            for name in default_name:
                try:
                    if type(f) is github.ContentFile.ContentFile:
                        f.name.lower().index(name)
                    elif type(f) is github.GitTreeElement.GitTreeElement:
                        f.path.lower().index(name)
                    return True
                except ValueError:
                    continue
            return False

        def get_current_folder_files(path, current_file, repository_config, g_repo, g_commit):
            """
            get the list of files of the current repository
            :param path: the path to the current file
            :param current_file: the current file
            :param repository_config: the repository configuration
            :param g_repo: the GitHub repository
            :return: the list of file of the current repository
            """
            files = []
            if current_file is None:
                return files, current_file
            if type(current_file) is not github.ContentFile.ContentFile:
                files = g_repo.get_git_tree(g_commit.sha)
                for f in current_file:
                    if is_default_file(f):
                        current_file = f
                        break
                if type(current_file) is not github.ContentFile.ContentFile:
                    current_file = current_file[0]
            elif current_file.type == 'file':
                if os.path.dirname(path) == '':
                    files = g_repo.get_git_tree(g_commit.sha)
                else:
                    f, folder = get_element_from_path(g_repo, g_commit, os.path.dirname(path))
                    if f is None:
                        files = folder
                    else:
                        files = g_repo.get_git_tree(f.sha)
            else:
                files = g_repo.get_git_tree(current_file.sha)
                for f in files.tree:
                    if is_default_file(f):
                        current_file, folder = get_element_from_path(g_repo, g_commit, os.path.join(path, f.path))
                        break
                if len(files.tree) == 1 and type(files.tree[0]) is github.ContentFile.ContentFile:
                    current_file, folder = get_element_from_path(g_repo, g_commit, os.path.join(path, files.tree[0].path))
            return files, current_file

        @application.route('/repository/<id>', methods=['GET'], defaults={'path': ''})
        @application.route('/repository/<id>/', methods=['GET'], defaults={'path': ''})
        @application.route('/repository/<id>/<path:path>', methods=['GET'])
        @application.route('/r/<id>', methods=['GET'], defaults={'path': ''})
        @application.route('/r/<id>/', methods=['GET'], defaults={'path': ''})
        @application.route('/r/<id>/<path:path>', methods=['GET'])
        def repository(id, path):
            repo_path = self.config_dir + "/" + str(id)
            config_path = repo_path + "/config.json"
            if not os.path.exists(config_path):
                return render_template('404.html'), 404
            with open(config_path, 'r') as f:
                repository_configuration = json.load(f, object_hook=json_util.object_hook)
                if 'expiration_date' in repository_configuration and repository_configuration['expiration_date'] is not None:
                    if repository_configuration['expiration_date'] <= datetime.now(repository_configuration['expiration_date'].tzinfo):
                        if repository_configuration['expiration'] == 'redirect':
                            return redirect(repository_configuration['repository'])
                        elif repository_configuration['expiration'] == 'remove':
                            return render_template('404.html'), 404
                (username, repo, branch) = clean_github_repository(repository_configuration['repository'])
                gh = self.github
                if 'token' in repository_configuration and repository_configuration['token'] is not None:
                    gh = github.Github(repository_configuration['token'])
                g_commit = None
                try:
                    g_repo = gh.get_repo("%s/%s" % (username, repo))
                    if branch is None:
                        branch = g_repo.default_branch
                    g_commit = g_repo.get_commit(branch)
                except:
                    return render_template('empty.html'), 404

                if not is_up_to_date(repository_configuration, g_commit):
                    if os.path.exists(os.path.join(repo_path, "cache")):
                        shutil.rmtree(os.path.join(repo_path, "cache"))
                    commit_date = datetime.strptime(g_commit.last_modified, "%a, %d %b %Y %H:%M:%S %Z")
                    repository_configuration["pushed_at"] = commit_date.strftime("%s")
                    with open(config_path, 'w') as fa:
                        json.dump(repository_configuration, fa, default=json_util.default)

                cache_path = os.path.join(self.config_dir, id, "cache")
                if os.path.isfile(os.path.join(cache_path, path)):
                    return send_from_directory(os.path.dirname(os.path.join(cache_path, path)),
                                               os.path.basename(os.path.join(cache_path, path)),
                                               mimetype=get_type_content(path, path, repository_configuration, g_repo, is_website(path, repository_configuration, g_repo)).replace("; charset=utf-8", ""))
                elif os.path.exists(os.path.join(cache_path, path, "index.html")):
                    return send_from_directory(os.path.join(cache_path, path), "index.html", mimetype='text/html')
                elif os.path.exists(os.path.join(cache_path, path, "README.md")):
                    return send_from_directory(os.path.join(cache_path, path), "README.md", mimetype='text/html')

                clean_path = path
                if len(clean_path) > 0 and clean_path[-1] == '/':
                    clean_path = clean_path[0:-1]
 
                current_file, files = get_element_from_path(g_repo, g_commit, clean_path)
                if current_file is None:
                    return render_template('404.html'), 404
                if type(current_file) == github.ContentFile.ContentFile and current_file.type == 'dir' and len(path) > 0 and path[-1] != '/':
                    return redirect(url_for('repository', id=id, path=path + '/'))

                files, current_file = get_current_folder_files(clean_path, current_file, repository_configuration, g_repo, g_commit)

                content = get_content(current_file, files, clean_path, repository_configuration, g_repo)
                content_type = get_type_content(current_file.name, clean_path, repository_configuration, g_repo, False)
                return content, {'Content-Type': content_type}

        @application.route('/', methods=['GET'])
        def index():
            id = request.args.get('id', None)
            repo_name = clean_github_repository(request.args.get('githubRepository', None))
            repo = None
            if id is not None:
                config_path = self.config_dir + "/" + id + "/config.json"
                if os.path.exists(config_path):
                    with open(config_path) as f:
                        data = json.load(f, object_hook=json_util.object_hook)
                        if repo_name == clean_github_repository(data['repository']):
                            repo = data
            return render_template('index.html', repo=repo)
        
        @application.route('/robots.txt')
        def robots():
            return application.send_static_file('robots.txt')

        @application.route('/', methods=['POST'])
        def add_repository():
            id = request.args.get('id', str(uuid.uuid4()))
            config_path = os.path.join(self.config_dir, str(id))
            
            repo = request.form['githubRepository']
            terms = request.form['terms']
            expiration_date = None
            expiration = None
            if 'expiration' in request.form:
                expiration = request.form['expiration']
            if 'expiration_date' in request.form and request.form['expiration_date'] != '':
                expiration_date = datetime.strptime(request.form['expiration_date'], '%Y-%m-%d')

            user = session.get('user', None)

            token = None
            if os.path.exists(config_path):
                with open(os.path.join(config_path, "config.json"), 'r') as r:
                    data = json.load(r)
                    if 'token' in data:
                       token = data['token']
            if token is None and user is not None and 'token' in user and user['token'] is not None:
                token = user['token']['access_token']
            
            if not os.path.exists(config_path):
                os.mkdir(config_path)
            with open(config_path + "/config.json", 'w') as outfile:
                json.dump({
                    "id": id,
                    "repository": repo,
                    "terms": terms.splitlines(),
                    "token": token,
                    "expiration_date": expiration_date,
                    "expiration": expiration
                }, outfile, default=json_util.default)
            return redirect(url_for('repository', id=id))

        return application