def guess_service(me): me = deproxyify(me) service = None # if we've previously registered, then it's easy site = Site.lookup_by_url(me) if site: service = site.service else: # otherwise we have to take an educated guess domain = util.domain_for_url(me).lower() current_app.logger.debug('guessing service by domain %s', domain) if domain.endswith('tumblr.com'): service = 'tumblr' elif domain.endswith('wordpress.com'): service = 'wordpress' elif domain.endswith('blogger.com'): service = 'blogger' elif domain == 'twitter.com': service = 'twitter' elif domain == 'facebook.com': service = 'facebook' elif domain == 'flickr.com': service = 'flickr' elif domain == 'github.com': service = 'github' elif domain == 'goodreads.com': service = 'goodreads' return service and SERVICES[service]
def indieauth_callback(): ia_params = session.get('indieauth_params', {}) me = ia_params.get('me') client_id = ia_params.get('client_id') redirect_uri = ia_params.get('redirect_uri') state = ia_params.get('state', '') scope = ia_params.get('scope', '') my_site = Site.lookup_by_url(deproxyify(me)) if not my_site: return redirect(util.set_query_params( redirect_uri, error='Authorization failed. Unknown site {}'.format(me))) result = SERVICES[my_site.service].process_authenticate_callback( url_for('.indieauth_callback', _external=True)) if 'error' in result: current_app.logger.warn('error on callback %s', result['error']) return redirect( util.set_query_params(redirect_uri, error=result['error'])) current_app.logger.debug('auth callback result %s', result) # check that the authorized user owns the requested site authed_account = Account.query.filter_by( service=my_site.service, user_id=result['user_id']).first() if not authed_account: current_app.logger.warn( 'Auth failed, unknown account %s', result['user_id']) return redirect(util.set_query_params( redirect_uri, error='Authorization failed. Unknown account {}' .format(result['user_id']))) if my_site.account != authed_account: return redirect(util.set_query_params( redirect_uri, error='Authorized account {} does not own requested site {}' .format(authed_account.username, my_site.domain))) # hand back a code to the micropub client code = binascii.hexlify(os.urandom(16)).decode() redis.setex('indieauth-code:{}'.format(code), datetime.timedelta(minutes=5), json.dumps({ 'site': my_site.id, 'me': me, 'redirect_uri': redirect_uri, 'client_id': client_id, 'state': state, 'scope': scope, })) return redirect(util.set_query_params( redirect_uri, me=me, state=state, code=code))
def indieauth(): # verify authorization if request.method == 'POST': code = request.form.get('code') client_id = request.form.get('client_id') redirect_uri = request.form.get('redirect_uri') state = request.form.get('state', '') datastr = redis.get('indieauth-code:{}'.format(code)) if not datastr: current_app.logger.warn('unrecognized auth code %s', code) return util.urlenc_response( {'error': 'Unrecognized or expired authorization code'}, 400) data = json.loads(datastr.decode('utf-8')) for key, value in [('client_id', client_id), ('redirect_uri', redirect_uri), ('state', state)]: if data.get(key) != value: current_app.logger.warn( '%s mismatch. expected=%s, received=%s', key, data.get(key), value) return util.urlenc_response({'error': key + ' mismatch'}, 400) me = data.get('me') return util.urlenc_response({'me': me}) # indieauth via the silo's authenication mechanism try: me = request.args.get('me') redirect_uri = request.args.get('redirect_uri') current_app.logger.info('get indieauth with me=%s and redirect=%s', me, redirect_uri) if not me or not redirect_uri: resp = make_response( "This is SiloPub's authorization endpoint. At least 'me' and " "'redirect_uri' are required.") resp.headers['IndieAuth'] = 'authorization_endpoint' return resp site = Site.lookup_by_url(deproxyify(me)) if not site: current_app.logger.warn('Auth failed, unknown site %s', me) return redirect(util.set_query_params( redirect_uri, error='Authorization failed. Unknown site {}' .format(me))) session['indieauth_params'] = { 'me': me, 'redirect_uri': redirect_uri, 'client_id': request.args.get('client_id'), 'state': request.args.get('state', ''), 'scope': request.args.get('scope', ''), } return redirect(SERVICES[site.service].get_authenticate_url( url_for('.indieauth_callback', _external=True), me=me)) except: current_app.logger.exception('Starting IndieAuth') if not redirect_uri: resp = make_response('Exception starting indieauth: {}'.format( str(sys.exc_info()[0])), 400) resp.headers['Content-Type'] = 'text/plain' return resp return redirect(util.set_query_params( redirect_uri, error=str(sys.exc_info()[0])))