Bundling webserver into RTV
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
include version.py
|
include version.py
|
||||||
include CHANGELOG.rst CONTRIBUTORS.rst LICENSE
|
include CHANGELOG.rst CONTRIBUTORS.rst LICENSE
|
||||||
|
include rtv/templates/*.html
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ def main():
|
|||||||
reddit.config.decode_html_entities = False
|
reddit.config.decode_html_entities = False
|
||||||
with curses_session() as stdscr:
|
with curses_session() as stdscr:
|
||||||
oauth = OAuthTool(reddit, stdscr, LoadScreen(stdscr))
|
oauth = OAuthTool(reddit, stdscr, LoadScreen(stdscr))
|
||||||
if args.auto_login == 'True':
|
if args.auto_login == 'True': # Ew!
|
||||||
oauth.authorize()
|
oauth.authorize()
|
||||||
if args.link:
|
if args.link:
|
||||||
page = SubmissionPage(stdscr, reddit, oauth, url=args.link)
|
page = SubmissionPage(stdscr, reddit, oauth, url=args.link)
|
||||||
@@ -160,8 +160,6 @@ def main():
|
|||||||
subreddit = args.subreddit or 'front'
|
subreddit = args.subreddit or 'front'
|
||||||
page = SubredditPage(stdscr, reddit, oauth, subreddit)
|
page = SubredditPage(stdscr, reddit, oauth, subreddit)
|
||||||
page.loop()
|
page.loop()
|
||||||
except praw.errors.InvalidUserPass:
|
|
||||||
print('Invalid password for username: {}'.format(args.username))
|
|
||||||
except praw.errors.OAuthAppRequired:
|
except praw.errors.OAuthAppRequired:
|
||||||
print('Invalid OAuth app config parameters')
|
print('Invalid OAuth app config parameters')
|
||||||
except praw.errors.OAuthInvalidToken:
|
except praw.errors.OAuthInvalidToken:
|
||||||
|
|||||||
@@ -10,5 +10,5 @@ OAuth settings
|
|||||||
|
|
||||||
oauth_client_id = 'nxoobnwO7mCP5A'
|
oauth_client_id = 'nxoobnwO7mCP5A'
|
||||||
oauth_client_secret = 'praw_gapfill'
|
oauth_client_secret = 'praw_gapfill'
|
||||||
oauth_redirect_uri = 'https://rtv.theo-piboubes.fr/auth'
|
oauth_redirect_uri = 'http://127.0.0.1:65000/auth'
|
||||||
oauth_scope = 'edit-history-identity-mysubreddits-privatemessages-read-report-save-submit-subscribe-vote'
|
oauth_scope = 'edit-history-identity-mysubreddits-privatemessages-read-report-save-submit-subscribe-vote'
|
||||||
|
|||||||
67
rtv/oauth.py
67
rtv/oauth.py
@@ -1,4 +1,4 @@
|
|||||||
import configparser
|
from six.moves import configparser
|
||||||
import curses
|
import curses
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -11,11 +11,37 @@ import praw
|
|||||||
from . import config
|
from . import config
|
||||||
from .curses_helpers import show_notification, prompt_input
|
from .curses_helpers import show_notification, prompt_input
|
||||||
|
|
||||||
|
from tornado import ioloop, web
|
||||||
|
|
||||||
__all__ = ['token_validity', 'OAuthTool']
|
__all__ = ['token_validity', 'OAuthTool']
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
token_validity = 3540
|
token_validity = 3540
|
||||||
|
|
||||||
|
oauth_state = None
|
||||||
|
oauth_code = None
|
||||||
|
oauth_error = None
|
||||||
|
|
||||||
|
class HomeHandler(web.RequestHandler):
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
self.render('home.html')
|
||||||
|
|
||||||
|
class AuthHandler(web.RequestHandler):
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
global oauth_state
|
||||||
|
global oauth_code
|
||||||
|
global oauth_error
|
||||||
|
|
||||||
|
oauth_state = self.get_argument('state', default='state_placeholder')
|
||||||
|
oauth_code = self.get_argument('code', default='code_placeholder')
|
||||||
|
oauth_error = self.get_argument('error', default='error_placeholder')
|
||||||
|
|
||||||
|
self.render('auth.html', state=oauth_state, code=oauth_code, error=oauth_error)
|
||||||
|
|
||||||
|
ioloop.IOLoop.current().stop()
|
||||||
|
|
||||||
class OAuthTool(object):
|
class OAuthTool(object):
|
||||||
|
|
||||||
def __init__(self, reddit, stdscr=None, loader=None,
|
def __init__(self, reddit, stdscr=None, loader=None,
|
||||||
@@ -38,6 +64,13 @@ class OAuthTool(object):
|
|||||||
|
|
||||||
self.token_expiration = 0
|
self.token_expiration = 0
|
||||||
|
|
||||||
|
# Initialize Tornado webapp and listen on port 65000
|
||||||
|
self.callback_app = web.Application([
|
||||||
|
(r'/', HomeHandler),
|
||||||
|
(r'/auth', AuthHandler),
|
||||||
|
], template_path='rtv/templates')
|
||||||
|
self.callback_app.listen(65000)
|
||||||
|
|
||||||
def get_config_fp(self):
|
def get_config_fp(self):
|
||||||
HOME = os.path.expanduser('~')
|
HOME = os.path.expanduser('~')
|
||||||
XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME',
|
XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME',
|
||||||
@@ -105,27 +138,37 @@ class OAuthTool(object):
|
|||||||
permission_ask_page_link = self.reddit.get_authorize_url(str(hex_uuid),
|
permission_ask_page_link = self.reddit.get_authorize_url(str(hex_uuid),
|
||||||
scope=self.scope, refreshable=True)
|
scope=self.scope, refreshable=True)
|
||||||
|
|
||||||
webbrowser.open(permission_ask_page_link)
|
with self.loader(message='Waiting for authorization'):
|
||||||
show_notification(self.stdscr, ['Access prompt opened in web browser'])
|
webbrowser.open(permission_ask_page_link)
|
||||||
|
|
||||||
final_state = prompt_input(self.stdscr, 'State: ')
|
ioloop.IOLoop.current().start()
|
||||||
final_code = prompt_input(self.stdscr, 'Code: ')
|
|
||||||
|
|
||||||
if not final_state or not final_code:
|
global oauth_state
|
||||||
curses.flash()
|
global oauth_code
|
||||||
|
global oauth_error
|
||||||
|
|
||||||
|
self.final_state = oauth_state
|
||||||
|
self.final_code = oauth_code
|
||||||
|
self.final_error = oauth_error
|
||||||
|
|
||||||
|
# Check if access was denied
|
||||||
|
if self.final_error == 'access_denied':
|
||||||
|
show_notification(self.stdscr, ['Declined access'])
|
||||||
|
return
|
||||||
|
elif self.final_error != 'error_placeholder':
|
||||||
|
show_notification(self.stdscr, ['Authentication error'])
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if UUID matches obtained state
|
# Check if UUID matches obtained state
|
||||||
# (if not, authorization process is compromised, and I'm giving up)
|
# (if not, authorization process is compromised, and I'm giving up)
|
||||||
if hex_uuid != final_state:
|
elif hex_uuid != self.final_state:
|
||||||
show_notification(self.stdscr, ['UUID mismatch, stopping.'])
|
show_notification(self.stdscr, ['UUID mismatch, stopping.'])
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get access information (tokens and scopes)
|
|
||||||
self.access_info = self.reddit.get_access_information(final_code)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self.loader(message='Logging in'):
|
with self.loader(message='Logging in'):
|
||||||
|
# Get access information (tokens and scopes)
|
||||||
|
self.access_info = self.reddit.get_access_information(self.final_code)
|
||||||
|
|
||||||
self.reddit.set_access_credentials(
|
self.reddit.set_access_credentials(
|
||||||
scope=set(self.access_info['scope']),
|
scope=set(self.access_info['scope']),
|
||||||
access_token=self.access_info['access_token'],
|
access_token=self.access_info['access_token'],
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -13,7 +13,7 @@ setup(
|
|||||||
keywords='reddit terminal praw curses',
|
keywords='reddit terminal praw curses',
|
||||||
packages=['rtv'],
|
packages=['rtv'],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=['praw>=3.1.0', 'six', 'requests', 'kitchen'],
|
install_requires=['tornado', 'praw>=3.1.0', 'six', 'requests', 'kitchen'],
|
||||||
entry_points={'console_scripts': ['rtv=rtv.__main__:main']},
|
entry_points={'console_scripts': ['rtv=rtv.__main__:main']},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Intended Audience :: End Users/Desktop',
|
'Intended Audience :: End Users/Desktop',
|
||||||
|
|||||||
Reference in New Issue
Block a user