<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:copyright: (c) 2015 by <NAME>
:license: MIT, see LICENSE for more details.

A Flask service to handle inbound HTML
events that IndieWeb Micropub requires.
"""

import os
import sys
import re
import uuid
import urllib
import logging

import redis
import ninka
import requests

from logging.handlers import RotatingFileHandler

from bearlib.config import Config
from bearlib.tools import baseDomain
from urlparse import ParseResult
from unidecode import unidecode

from flask import Flask, request, redirect, render_template, session
from flask.ext.wtf import Form
from wtforms import TextField, HiddenField
from wtforms.validators import Required


class LoginForm(Form):
    me           = TextField('me', validators=[ Required() ])
    client_id    = HiddenField('client_id')
    redirect_uri = HiddenField('redirect_uri')
    from_uri     = HiddenField('from_uri')

class PubishForm(Form):
    h            = TextField('h', validators=[])
    content      = TextField('content', validators=[])
    title        = TextField('title', validators=[])
    published    = TextField('published', validators=[])
    inreplyto    = TextField('in-reply-to', validators=[])
    syndicateto  = TextField('syndicate-to', validators=[])

class TokenForm(Form):
    # app_id     = TextField('app_id', validators = [ Required() ])
    # invalidate = BooleanField('invalidate')
    # app_token  = TextField('app_token')
    # client_id  = HiddenField('client_id')
    code         = TextField('code', validators=[])
    me           = TextField('me', validators=[])
    redirect_uri = TextField('redirect_uri', validators=[])
    client_id    = TextField('client_id', validators=[])
    state        = TextField('state', validators=[])


# check for uwsgi, use PWD if present or getcwd() if not
_uwsgi = __name__.startswith('uwsgi')
if _uwsgi:
    # TODO: need to find a better way - both / and . are replaced with _ for paths
    #       which can generate bad paths with the simplistic replace i'm doing below
    _ourPath    = os.path.dirname(__name__.replace('uwsgi_file_', '').replace('_', '/'))
    _configFile = '/etc/kaku.cfg'
    if not os.path.exists('/etc/kaku.cfg'):
        _configFile = os.path.join(_ourPath, 'kaku.cfg')
    sys.path.append(_ourPath)
else:
    _ourPath    = os.getcwd()
    _configFile = os.path.join(_ourPath, 'kaku.cfg')

# these are done here instead of at top to allow the path to be inserted above
from handlers.webmention import mention
from handlers.micropub import micropub

app = Flask(__name__)
app.config['SECRET_KEY'] = 'foo'  # replaced downstream
cfg = None
db  = None


# from http://flask.pocoo.org/snippets/5/
_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
def createSlug(text, delim=u'-'):
    result = []
    for word in _punct_re.split(text.lower()):
        result.extend(unidecode(word).split())
    return unicode(delim.join(result))

def clearAuth():
    if 'indieauth_token' in session:
        if db is not None:
            key = db.get('token-%s' % session['indieauth_token'])
            if key:
                db.delete(key)
                db.delete('token-%s' % session['indieauth_token'])
    session.pop('indieauth_token', None)
    session.pop('indieauth_scope', None)
    session.pop('indieauth_id',    None)

def checkAuth():
    authed        = False
    indieauth_id  = None
    if 'indieauth_id' in session and 'indieauth_token' in session:
        app.logger.info('session cookie found')
        indieauth_id    = session['indieauth_id']
        indieauth_token = session['indieauth_token']
        if db is not None:
            key = db.get('token-%s' % indieauth_token)
            if key:
                data = db.hgetall(key)
                if data and data['token'] == indieauth_token:
                    authed = True
    return authed, indieauth_id

def checkAccessToken(access_token):
    if access_token is not None and db is not None:
        key = db.get('token-%s' % access_token)
        if key:
            data      = key.split('-')
            me        = data[1]
            client_id = data[2]
            scope     = data[3]
            app.logger.info('access token valid [%s] [%s] [%s]' % (me, client_id, scope))
            return me, client_id, scope
    else:
        return None, None, None

@app.route('/logout', methods=['GET'])
def handleLogout():
    app.logger.info('handleLogout [%s]' % request.method)
    clearAuth()
    return redirect('/')

@app.route('/login', methods=['GET', 'POST'])
def handleLogin():
    app.logger.info('handleLogin [%s]' % request.method)

    me          = None
    redirectURI = '%s/success' % cfg.baseurl
    fromURI     = request.args.get('from_uri')
    # if fromURI is None:
    #     fromURI = '%s/login' % cfg.baseurl
    app.logger.info('redirectURI [%s] fromURI [%s]' % (redirectURI, fromURI))
    form = LoginForm(me='',
                     client_id=cfg.client_id,
                     redirect_uri=redirectURI,
                     from_uri=fromURI)

    if form.validate_on_submit():
        app.logger.info('me [%s]' % form.me.data)

        me            = 'https://%s/' % baseDomain(form.me.data, includeScheme=False)
        authEndpoints = ninka.indieauth.discoverAuthEndpoints(me)

        if 'authorization_endpoint' in authEndpoints:
            authURL = None
            for url in authEndpoints['authorization_endpoint']:
                authURL = url
                break
            if authURL is not None:
                url = ParseResult(authURL.scheme,
                                  authURL.netloc,
                                  authURL.path,
                                  authURL.params,
                                  urllib.urlencode({ 'me':            me,
                                                     'redirect_uri':  form.redirect_uri.data,
                                                     'client_id':     form.client_id.data,
                                                     'scope':         'post',
                                                     'response_type': 'id'
                                                   }),
                                  authURL.fragment).geturl()
                if db is not None:
                    key  = 'login-%s' % me
                    data = db.hgetall(key)
                    if data and 'token' in data:  # clear any existing auth data
                        db.delete('token-%s' % data['token'])
                        db.hdel(key, 'token')
                    db.hset(key, 'from_uri',     form.from_uri.data)
                    db.hset(key, 'redirect_uri', form.redirect_uri.data)
                    db.hset(key, 'client_id',    form.client_id.data)
                    db.hset(key, 'scope',        'post')
                    db.expire(key, cfg.auth_timeout)  # expire in N minutes unless successful
                app.logger.info('redirecting to [%s]' % url)
                return redirect(url)
        else:
            return 'insert fancy no auth endpoint found error message here', 403

    templateContext = {}
    templateContext['title'] = 'Sign In'
    templateContext['form']  = form<commit_msg>missed setting of auth_uri during login event<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
:copyright: (c) 2015 by <NAME>
:license: MIT, see LICENSE for more details.

A Flask service to handle inbound HTML
events that IndieWeb Micropub requires.
"""

import os
import sys
import re
import uuid
import urllib
import logging

import redis
import ninka
import requests

from logging.handlers import RotatingFileHandler

from bearlib.config import Config
from bearlib.tools import baseDomain
from urlparse import ParseResult
from unidecode import unidecode

from flask import Flask, request, redirect, render_template, session
from flask.ext.wtf import Form
from wtforms import TextField, HiddenField
from wtforms.validators import Required


class LoginForm(Form):
    me           = TextField('me', validators=[ Required() ])
    client_id    = HiddenField('client_id')
    redirect_uri = HiddenField('redirect_uri')
    from_uri     = HiddenField('from_uri')

class PubishForm(Form):
    h            = TextField('h', validators=[])
    content      = TextField('content', validators=[])
    title        = TextField('title', validators=[])
    published    = TextField('published', validators=[])
    inreplyto    = TextField('in-reply-to', validators=[])
    syndicateto  = TextField('syndicate-to', validators=[])

class TokenForm(Form):
    # app_id     = TextField('app_id', validators = [ Required() ])
    # invalidate = BooleanField('invalidate')
    # app_token  = TextField('app_token')
    # client_id  = HiddenField('client_id')
    code         = TextField('code', validators=[])
    me           = TextField('me', validators=[])
    redirect_uri = TextField('redirect_uri', validators=[])
    client_id    = TextField('client_id', validators=[])
    state        = TextField('state', validators=[])


# check for uwsgi, use PWD if present or getcwd() if not
_uwsgi = __name__.startswith('uwsgi')
if _uwsgi:
    # TODO: need to find a better way - both / and . are replaced with _ for paths
    #       which can generate bad paths with the simplistic replace i'm doing below
    _ourPath    = os.path.dirname(__name__.replace('uwsgi_file_', '').replace('_', '/'))
    _configFile = '/etc/kaku.cfg'
    if not os.path.exists('/etc/kaku.cfg'):
        _configFile = os.path.join(_ourPath, 'kaku.cfg')
    sys.path.append(_ourPath)
else:
    _ourPath    = os.getcwd()
    _configFile = os.path.join(_ourPath, 'kaku.cfg')

# these are done here instead of at top to allow the path to be inserted above
from handlers.webmention import mention
from handlers.micropub import micropub

app = Flask(__name__)
app.config['SECRET_KEY'] = 'foo'  # replaced downstream
cfg = None
db  = None


# from http://flask.pocoo.org/snippets/5/
_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
def createSlug(text, delim=u'-'):
    result = []
    for word in _punct_re.split(text.lower()):
        result.extend(unidecode(word).split())
    return unicode(delim.join(result))

def clearAuth():
    if 'indieauth_token' in session:
        if db is not None:
            key = db.get('token-%s' % session['indieauth_token'])
            if key:
                db.delete(key)
                db.delete('token-%s' % session['indieauth_token'])
    session.pop('indieauth_token', None)
    session.pop('indieauth_scope', None)
    session.pop('indieauth_id',    None)

def checkAuth():
    authed        = False
    indieauth_id  = None
    if 'indieauth_id' in session and 'indieauth_token' in session:
        app.logger.info('session cookie found')
        indieauth_id    = session['indieauth_id']
        indieauth_token = session['indieauth_token']
        if db is not None:
            key = db.get('token-%s' % indieauth_token)
            if key:
                data = db.hgetall(key)
                if data and data['token'] == indieauth_token:
                    authed = True
    return authed, indieauth_id

def checkAccessToken(access_token):
    if access_token is not None and db is not None:
        key = db.get('token-%s' % access_token)
        if key:
            data      = key.split('-')
            me        = data[1]
            client_id = data[2]
            scope     = data[3]
            app.logger.info('access token valid [%s] [%s] [%s]' % (me, client_id, scope))
            return me, client_id, scope
    else:
        return None, None, None

@app.route('/logout', methods=['GET'])
def handleLogout():
    app.logger.info('handleLogout [%s]' % request.method)
    clearAuth()
    return redirect('/')

@app.route('/login', methods=['GET', 'POST'])
def handleLogin():
    app.logger.info('handleLogin [%s]' % request.method)

    me          = None
    redirectURI = '%s/success' % cfg.baseurl
    fromURI     = request.args.get('from_uri')
    # if fromURI is None:
    #     fromURI = '%s/login' % cfg.baseurl
    app.logger.info('redirectURI [%s] fromURI [%s]' % (redirectURI, fromURI))
    form = LoginForm(me='',
                     client_id=cfg.client_id,
                     redirect_uri=redirectURI,
                     from_uri=fromURI)

    if form.validate_on_submit():
        app.logger.info('me [%s]' % form.me.data)

        me            = 'https://%s/' % baseDomain(form.me.data, includeScheme=False)
        authEndpoints = ninka.indieauth.discoverAuthEndpoints(me)

        if 'authorization_endpoint' in authEndpoints:
            authURL = None
            for url in authEndpoints['authorization_endpoint']:
                authURL = url
                break
            if authURL is not None:
                url = ParseResult(authURL.scheme,
                                  authURL.netloc,
                                  authURL.path,
                                  authURL.params,
                                  urllib.urlencode({ 'me':            me,
                                                     'redirect_uri':  form.redirect_uri.data,
                                                     'client_id':     form.client_id.data,
                                                     'scope':         'post',
                                                     'response_type': 'id'
                                                   }),
                                  authURL.fragment).geturl()
                if db is not None:
                    key  = 'login-%s' % me
                    data = db.hgetall(key)
                    if data and 'token' in data:  # clear any existing auth data
                        db.delete('token-%s' % data['token'])
                        db.hdel(key, 'token')
                    db.hset(key, 'auth_url',     ParseResult(authURL.scheme, authURL.netloc, authURL.path, '', '', '').geturl())
                    db.hset(key, 'from_uri',     form.from_uri.data)
                    db.hset(key, 'redirect_uri', form.redirect_uri.data)
                    db.hset(key, 'client_id',    form.client_id.data)
                    db.hset(key, 'scope',        'post')
                    db.expire(key, cfg.auth_timeout)  # expire in N minutes unless successful
                app.logger.info('redirecting to [%s]' % url)
                return redirect(url)
        else:
            return 'insert fancy no auth endpoint found error message here', 403

    templateContext = {}
    templateContext['title'] = 'Sign In'
    templateContext['form']  = form
{'fraction_non_alphanumeric': 0.12072846326989974, 'fraction_numerical': 0.0016369961121342337, 'mean_word_length': 2.033098882912702, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6446977', 'n_tokens_mistral': 4390, 'n_tokens_neox': 4238, 'n_words': 1057}