From 6cc744bf91eeb199f63ea9236cac9ea7821ee59b Mon Sep 17 00:00:00 2001 From: Michael Lazar Date: Sun, 20 Sep 2015 19:54:41 -0700 Subject: [PATCH] Tweaking a few things oauth things. --- MANIFEST.in | 2 +- rtv/__main__.py | 137 ++++++----------------- rtv/config.py | 58 ++++++++-- rtv/docs.py | 12 +- rtv/helpers.py | 38 ++++--- rtv/oauth.py | 235 +++++++++++++++------------------------- rtv/page.py | 9 +- rtv/submission.py | 5 +- rtv/subscription.py | 1 - rtv/templates/auth.html | 15 --- rtv/templates/home.html | 3 - templates/index.html | 43 ++++++++ 12 files changed, 244 insertions(+), 314 deletions(-) delete mode 100644 rtv/templates/auth.html delete mode 100644 rtv/templates/home.html create mode 100644 templates/index.html diff --git a/MANIFEST.in b/MANIFEST.in index 02ad4bd..1d70d56 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include version.py include CHANGELOG.rst CONTRIBUTORS.rst LICENSE -include rtv/templates/*.html +include rtv/templates/* diff --git a/rtv/__main__.py b/rtv/__main__.py index 0096031..3cc8c6c 100644 --- a/rtv/__main__.py +++ b/rtv/__main__.py @@ -7,7 +7,7 @@ import logging import requests import praw import praw.errors -from six.moves import configparser +import tornado from . import config from .exceptions import SubmissionError, SubredditError, SubscriptionError, ProgramError @@ -18,70 +18,14 @@ from .docs import * from .oauth import OAuthTool from .__version__ import __version__ -from tornado import ioloop - __all__ = [] -def load_rtv_config(): - """ - Attempt to load saved settings for things like the username and password. - """ - - config = configparser.ConfigParser() - - HOME = os.path.expanduser('~') - XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', - os.path.join(HOME, '.config')) - - config_paths = [ - os.path.join(XDG_CONFIG_HOME, 'rtv', 'rtv.cfg'), - os.path.join(HOME, '.rtv') - ] - - # get the first existing config file - for config_path in config_paths: - if os.path.exists(config_path): - config.read(config_path) - break - - defaults = {} - if config.has_section('rtv'): - defaults = dict(config.items('rtv')) - - if 'ascii' in defaults: - defaults['ascii'] = config.getboolean('rtv', 'ascii') - - return defaults - -def load_oauth_config(): - """ - Attempt to load saved OAuth settings - """ - - config = configparser.ConfigParser() - - HOME = os.path.expanduser('~') - XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', - os.path.join(HOME, '.config')) - - if os.path.exists(os.path.join(XDG_CONFIG_HOME, 'rtv')): - config_path = os.path.join(XDG_CONFIG_HOME, 'rtv', 'oauth.cfg') - else: - config_path = os.path.join(HOME, '.rtv-oauth') - - config.read(config_path) - - if config.has_section('oauth'): - defaults = dict(config.items('oauth')) - else: - # Populate OAuth section - config.add_section('oauth') - config.set('oauth', 'auto_login', 'false') - with open(config_path, 'w') as cfg: - config.write(cfg) - defaults = dict(config.items('oauth')) - - return defaults +# Pycharm debugging note: +# You can use pycharm to debug a curses application by launching rtv in a +# console window (python -m rtv) and using pycharm to attach to the remote +# process. On Ubuntu, you may need to allow ptrace permissions by setting +# ptrace_scope to 0 in /etc/sysctl.d/10-ptrace.conf. +# http://blog.mellenthin.de/archives/2010/10/18/gdb-attach-fails def command_line(): @@ -90,59 +34,46 @@ def command_line(): epilog=CONTROLS + HELP, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('-s', dest='subreddit', help='subreddit name') - parser.add_argument('-l', dest='link', help='full link to a submission') - parser.add_argument('--ascii', action='store_true', - help='enable ascii-only mode') - parser.add_argument('--log', metavar='FILE', action='store', - help='Log HTTP requests') - - group = parser.add_argument_group('authentication (optional)', AUTH) - group.add_argument('-u', dest='username', help='reddit username') - group.add_argument('-p', dest='password', help='reddit password') - - oauth_group = parser.add_argument_group('OAuth data (optional)', OAUTH) - oauth_group.add_argument('--auto-login', dest='auto_login', help='OAuth auto-login setting') - oauth_group.add_argument('--refresh-token', dest='refresh_token', help='OAuth refresh token') - + parser.add_argument('-s', dest='subreddit', help='name of the subreddit that will be opened on start') + parser.add_argument('-l', dest='link', help='full URL of a submission that will be opened on start') + parser.add_argument('--ascii', action='store_true', help='enable ascii-only mode') + parser.add_argument('--log', metavar='FILE', action='store', help='log HTTP requests to a file') + parser.add_argument('--refresh-token', dest='refresh_token', help='OAuth refresh token') + parser.add_argument('--clear-session', dest='clear_session', action='store_true', help='Remove any saved OAuth tokens before starting') args = parser.parse_args() return args - def main(): "Main entry point" - # logging.basicConfig(level=logging.DEBUG, filename='rtv.log') + # Squelch SSL warnings + logging.captureWarnings(True) locale.setlocale(locale.LC_ALL, '') - args = command_line() - local_rtv_config = load_rtv_config() - local_oauth_config = load_oauth_config() - - # set the terminal title + # Set the terminal title title = 'rtv {0}'.format(__version__) if os.name == 'nt': os.system('title {0}'.format(title)) else: sys.stdout.write("\x1b]2;{0}\x07".format(title)) - # Fill in empty arguments with config file values. Paramaters explicitly + # Fill in empty arguments with config file values. Parameters explicitly # typed on the command line will take priority over config file params. - for key, val in local_rtv_config.items(): + args = command_line() + local_config = config.load_config() + for key, val in local_config.items(): if getattr(args, key, None) is None: setattr(args, key, val) - for k, v in local_oauth_config.items(): - if getattr(args, k, None) is None: - setattr(args, k, v) - - config.unicode = (not args.ascii) - - # Squelch SSL warnings for Ubuntu - logging.captureWarnings(True) + if args.ascii: + config.unicode = False if args.log: logging.basicConfig(level=logging.DEBUG, filename=args.log) + if args.clear_session: + config.clear_refresh_token() + if args.refresh_token: + config.save_refresh_token(args.refresh_token) try: print('Connecting...') @@ -150,21 +81,21 @@ def main(): reddit.config.decode_html_entities = False with curses_session() as stdscr: oauth = OAuthTool(reddit, stdscr, LoadScreen(stdscr)) - if args.auto_login == 'true': # Ew! + if oauth.refresh_token: oauth.authorize() + if args.link: page = SubmissionPage(stdscr, reddit, oauth, url=args.link) page.loop() subreddit = args.subreddit or 'front' page = SubredditPage(stdscr, reddit, oauth, subreddit) page.loop() - except (praw.errors.OAuthAppRequired, praw.errors.OAuthInvalidToken, - praw.errors.HTTPException) as e: + except (praw.errors.OAuthAppRequired, praw.errors.OAuthInvalidToken): print('Invalid OAuth data') - except requests.ConnectionError: - print('Connection timeout') - except requests.HTTPError: + except praw.errors.NotFound: print('HTTP Error: 404 Not Found') + except praw.errors.HTTPException: + print('Connection timeout') except SubmissionError as e: print('Could not reach submission URL: {}'.format(e.url)) except SubredditError as e: @@ -178,6 +109,6 @@ def main(): # Ensure sockets are closed to prevent a ResourceWarning reddit.handler.http.close() # Explicitly close file descriptors opened by Tornado's IOLoop - ioloop.IOLoop.current().close(all_fds=True) + tornado.ioloop.IOLoop.current().close(all_fds=True) -sys.exit(main()) +sys.exit(main()) \ No newline at end of file diff --git a/rtv/config.py b/rtv/config.py index 53f4c59..24eeec0 100644 --- a/rtv/config.py +++ b/rtv/config.py @@ -1,14 +1,58 @@ """ Global configuration settings """ +import os +from six.moves import configparser + +HOME = os.path.expanduser('~') +XDG_HOME = os.getenv('XDG_CONFIG_HOME', os.path.join(HOME, '.config')) +CONFIG = os.path.join(XDG_HOME, 'rtv', 'rtv.cfg') +TOKEN = os.path.join(XDG_HOME, 'rtv', 'refresh-token') unicode = True -""" -OAuth settings -""" - -oauth_client_id = 'nxoobnwO7mCP5A' +# https://github.com/reddit/reddit/wiki/OAuth2 +# Client ID is of type "installed app" and the secret should be left empty +oauth_client_id = 'E2oEtRQfdfAfNQ' oauth_client_secret = 'praw_gapfill' -oauth_redirect_uri = 'http://127.0.0.1:65000/auth' -oauth_scope = 'edit-history-identity-mysubreddits-privatemessages-read-report-save-submit-subscribe-vote' +oauth_redirect_uri = 'http://127.0.0.1:65000/' +oauth_redirect_port = 65000 +oauth_scope = ['edit', 'history', 'identity', 'mysubreddits', 'privatemessages', + 'read', 'report', 'save', 'submit', 'subscribe', 'vote'] + +def load_config(): + """ + Attempt to load settings from the local config file. + """ + + config = configparser.ConfigParser() + if os.path.exists(CONFIG): + config.read(CONFIG) + + config_dict = {} + if config.has_section('rtv'): + config_dict = dict(config.items('rtv')) + + # Convert 'true'/'false' to boolean True/False + if 'ascii' in config_dict: + config_dict['ascii'] = config.getboolean('rtv', 'ascii') + if 'clear_session' in config_dict: + config_dict['clear_session'] = config.getboolean('rtv', 'clear_session') + if 'oauth_scope' in config_dict: + config_dict['oauth_scope'] = config.oauth_scope.split('-') + return config_dict + +def load_refresh_token(filename=TOKEN): + if os.path.exists(filename): + with open(filename) as fp: + return fp.read().strip() + else: + return None + +def save_refresh_token(token, filename=TOKEN): + with open(filename, 'w+') as fp: + fp.write(token) + +def clear_refresh_token(filename=TOKEN): + if os.path.exists(filename): + os.remove(filename) \ No newline at end of file diff --git a/rtv/docs.py b/rtv/docs.py index a4cba11..66aa6c2 100644 --- a/rtv/docs.py +++ b/rtv/docs.py @@ -1,6 +1,6 @@ from .__version__ import __version__ -__all__ = ['AGENT', 'SUMMARY', 'AUTH', 'OAUTH', 'CONTROLS', 'HELP', 'COMMENT_FILE', +__all__ = ['AGENT', 'SUMMARY', 'CONTROLS', 'HELP', 'COMMENT_FILE', 'SUBMISSION_FILE', 'COMMENT_EDIT_FILE'] AGENT = """\ @@ -12,16 +12,6 @@ Reddit Terminal Viewer is a lightweight browser for www.reddit.com built into a terminal window. """ -AUTH = """\ -Authenticating is required to vote and leave comments. If only a username is -given, the program will display a secure prompt to enter a password. -""" - -OAUTH = """\ -Authentication is now done by OAuth, since PRAW will drop -password authentication soon. -""" - CONTROLS = """ Controls -------- diff --git a/rtv/helpers.py b/rtv/helpers.py index e07434e..274ad73 100644 --- a/rtv/helpers.py +++ b/rtv/helpers.py @@ -102,21 +102,7 @@ def open_browser(url): are not detected here. """ - console_browsers = ['www-browser', 'links', 'links2', 'elinks', 'lynx', 'w3m'] - - display = bool(os.environ.get("DISPLAY")) - - # Use the convention defined here to parse $BROWSER - # https://docs.python.org/2/library/webbrowser.html - if "BROWSER" in os.environ: - user_browser = os.environ["BROWSER"].split(os.pathsep)[0] - if user_browser in console_browsers: - display = False - - if webbrowser._tryorder and webbrowser._tryorder[0] in console_browsers: - display = False - - if display: + if check_browser_display(): command = "import webbrowser; webbrowser.open_new_tab('%s')" % url args = [sys.executable, '-c', command] with open(os.devnull, 'ab+', 0) as null: @@ -127,6 +113,28 @@ def open_browser(url): curses.doupdate() +def check_browser_display(): + """ + Use a number of methods to guess if the default webbrowser will open in + the background as opposed to opening directly in the terminal. + """ + + display = bool(os.environ.get("DISPLAY")) + + # Use the convention defined here to parse $BROWSER + # https://docs.python.org/2/library/webbrowser.html + console_browsers = ['www-browser', 'links', 'links2', 'elinks', 'lynx', 'w3m'] + if "BROWSER" in os.environ: + user_browser = os.environ["BROWSER"].split(os.pathsep)[0] + if user_browser in console_browsers: + display = False + + if webbrowser._tryorder and webbrowser._tryorder[0] in console_browsers: + display = False + + return display + + def wrap_text(text, width): """ Wrap text paragraphs to the given character width while preserving newlines. diff --git a/rtv/oauth.py b/rtv/oauth.py index 6a51ada..4bd6122 100644 --- a/rtv/oauth.py +++ b/rtv/oauth.py @@ -1,185 +1,120 @@ -import curses -import logging import os import time import uuid -import webbrowser import praw -from six.moves import configparser - -from . import config -from .curses_helpers import show_notification, prompt_input - from tornado import gen, ioloop, web, httpserver from concurrent.futures import ThreadPoolExecutor -__all__ = ['token_validity', 'OAuthTool'] -_logger = logging.getLogger(__name__) +from . import config +from .curses_helpers import show_notification, prompt_input +from .helpers import check_browser_display, open_browser + +__all__ = ['OAuthTool'] 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 initialize(self): - self.compact = os.environ.get('BROWSER') in ['w3m', 'links', 'elinks', 'lynx'] - def get(self): - global oauth_state - global oauth_code - global oauth_error + global oauth_state, oauth_code, 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') + oauth_state = self.get_argument('state', default='placeholder') + oauth_code = self.get_argument('code', default='placeholder') + oauth_error = self.get_argument('error', default='placeholder') - self.render('auth.html', state=oauth_state, code=oauth_code, error=oauth_error) + self.render('index.html', state=oauth_state, code=oauth_code, error=oauth_error) - # Stop IOLoop if using BackgroundBrowser (or GUI browser) - if not self.compact: + # Stop IOLoop if using a background browser such as firefox + if check_browser_display(): ioloop.IOLoop.current().stop() class OAuthTool(object): - def __init__(self, reddit, stdscr=None, loader=None, - client_id=None, redirect_uri=None, scope=None): + def __init__(self, reddit, stdscr=None, loader=None): + self.reddit = reddit self.stdscr = stdscr self.loader = loader - - self.config = configparser.ConfigParser() - self.config_fp = None - - self.client_id = client_id or config.oauth_client_id - # Comply with PRAW's desperate need for client secret - self.client_secret = config.oauth_client_secret - self.redirect_uri = redirect_uri or config.oauth_redirect_uri - - self.scope = scope or config.oauth_scope.split('-') - self.access_info = {} - - # Terminal web browser - self.compact = os.environ.get('BROWSER') in ['w3m', 'links', 'elinks', 'lynx'] - - # Initialize Tornado webapp - self.callback_app = web.Application([ - (r'/', HomeHandler), - (r'/auth', AuthHandler), - ], template_path='rtv/templates') - self.http_server = None - def get_config_fp(self): - HOME = os.path.expanduser('~') - XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', - os.path.join(HOME, '.config')) + self.refresh_token = config.load_refresh_token() - if os.path.exists(os.path.join(XDG_CONFIG_HOME, 'rtv')): - file_path = os.path.join(XDG_CONFIG_HOME, 'rtv', 'oauth.cfg') - else: - file_path = os.path.join(HOME, '.rtv-oauth') + # Initialize Tornado webapp + routes = [('/', AuthHandler)] + self.callback_app = web.Application(routes, template_path='templates') - return file_path + self.reddit.set_oauth_app_info(config.oauth_client_id, + config.oauth_client_secret, + config.oauth_redirect_uri) - def open_config(self, update=False): - if self.config_fp is None: - self.config_fp = self.get_config_fp() - - if update: - self.config.read(self.config_fp) - - def save_config(self): - self.open_config() - with open(self.config_fp, 'w') as cfg: - self.config.write(cfg) - - def clear_oauth_data(self): - self.open_config(update=True) - if self.config.has_section('oauth') and self.config.has_option('oauth', 'refresh_token'): - self.config.remove_option('oauth', 'refresh_token') - self.save_config() - - @gen.coroutine - def open_terminal_browser(self, url): - with ThreadPoolExecutor(max_workers=1) as executor: - yield executor.submit(webbrowser.open_new_tab, url) - - ioloop.IOLoop.current().stop() + # Reddit's mobile website works better on terminal browsers + if not check_browser_display(): + if '.compact' not in self.reddit.config.API_PATHS['authorize']: + self.reddit.config.API_PATHS['authorize'] += '.compact' def authorize(self): - if self.compact and not '.compact' in self.reddit.config.API_PATHS['authorize']: - self.reddit.config.API_PATHS['authorize'] += '.compact' - self.reddit.set_oauth_app_info(self.client_id, - self.client_secret, - self.redirect_uri) - - self.open_config(update=True) - # If no previous OAuth data found, starting from scratch - if not self.config.has_section('oauth') or not self.config.has_option('oauth', 'refresh_token'): - if self.http_server is None: - self.http_server = httpserver.HTTPServer(self.callback_app) - self.http_server.listen(65000) - - # Generate a random UUID - hex_uuid = uuid.uuid4().hex - - permission_ask_page_link = self.reddit.get_authorize_url(str(hex_uuid), - scope=self.scope, refreshable=True) - - if self.compact: - show_notification(self.stdscr, ['Opening ' + os.environ.get('BROWSER')]) - curses.endwin() - ioloop.IOLoop.current().add_callback(self.open_terminal_browser, permission_ask_page_link) - ioloop.IOLoop.current().start() - curses.doupdate() - else: - with self.loader(message='Waiting for authorization'): - webbrowser.open(permission_ask_page_link) - ioloop.IOLoop.current().start() - - global oauth_state - 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 - - # Check if UUID matches obtained state - # (if not, authorization process is compromised, and I'm giving up) - if hex_uuid != self.final_state: - show_notification(self.stdscr, ['UUID mismatch, stopping.']) - return - - try: - with self.loader(message='Logging in'): - # Get access information (tokens and scopes) - self.access_info = self.reddit.get_access_information(self.final_code) - except (praw.errors.OAuthAppRequired, praw.errors.OAuthInvalidToken) as e: - show_notification(self.stdscr, ['Invalid OAuth data']) - else: - if not self.config.has_section('oauth'): - self.config.add_section('oauth') - - self.config.set('oauth', 'refresh_token', self.access_info['refresh_token']) - self.save_config() - # Otherwise, fetch new access token - else: + # If we already have a token, request new access credentials + if self.refresh_token: with self.loader(message='Logging in'): - self.reddit.refresh_access_information(self.config.get('oauth', 'refresh_token')) + self.reddit.refresh_access_information(self.refresh_token) + return + + # Start the authorization callback server + if self.http_server is None: + self.http_server = httpserver.HTTPServer(self.callback_app) + self.http_server.listen(config.oauth_redirect_port) + + hex_uuid = uuid.uuid4().hex + authorize_url = self.reddit.get_authorize_url( + hex_uuid, scope=config.oauth_scope, refreshable=True) + + # Open the browser and wait for the user to authorize the app + if check_browser_display(): + with self.loader(message='Waiting for authorization'): + open_browser(authorize_url) + ioloop.IOLoop.current().start() + else: + with self.loader(delay=0, message='Redirecting to reddit'): + # Provide user feedback + time.sleep(1) + ioloop.IOLoop.current().add_callback(self._open_authorize_url, + authorize_url) + ioloop.IOLoop.current().start() + + if oauth_error == 'access_denied': + show_notification(self.stdscr, ['Declined access']) + return + elif oauth_error != 'placeholder': + show_notification(self.stdscr, ['Authentication error']) + return + elif hex_uuid != oauth_state: + # Check if UUID matches obtained state. + # If not, authorization process is compromised. + show_notification(self.stdscr, ['UUID mismatch']) + return + + try: + with self.loader(message='Logging in'): + access_info = self.reddit.get_access_information(oauth_code) + config.save_refresh_token(access_info['refresh_token']) + self.refresh_token = access_info['refresh_token'] + except (praw.errors.OAuthAppRequired, praw.errors.OAuthInvalidToken): + show_notification(self.stdscr, ['Invalid OAuth data']) + else: + message = ['Welcome {}!'.format(self.reddit.user.name)] + show_notification(self.stdscr, message) + + def clear_oauth_data(self): + self.reddit.clear_authentication() + config.clear_refresh_token() + self.refresh_token = None + + @gen.coroutine + def _open_authorize_url(self, url): + with ThreadPoolExecutor(max_workers=1) as executor: + yield executor.submit(open_browser, url) + ioloop.IOLoop.current().stop() diff --git a/rtv/page.py b/rtv/page.py index 34a5467..a51fb46 100644 --- a/rtv/page.py +++ b/rtv/page.py @@ -239,7 +239,7 @@ class BaseController(object): class BasePage(object): """ - Base terminal viewer incorperates a cursor to navigate content + Base terminal viewer incorporates a cursor to navigate content """ MIN_HEIGHT = 10 @@ -351,11 +351,10 @@ class BasePage(object): """ if self.reddit.is_oauth_session(): - self.reddit.clear_authentication() self.oauth.clear_oauth_data() - return - - self.oauth.authorize() + show_notification(self.stdscr, ['Logged out']) + else: + self.oauth.authorize() @BaseController.register('d') def delete(self): diff --git a/rtv/submission.py b/rtv/submission.py index f5aba23..9044bd5 100644 --- a/rtv/submission.py +++ b/rtv/submission.py @@ -24,7 +24,6 @@ class SubmissionPage(BasePage): self.controller = SubmissionController(self) self.loader = LoadScreen(stdscr) - self.oauth = oauth if url: content = SubmissionContent.from_url(reddit, url, self.loader) elif submission: @@ -32,8 +31,8 @@ class SubmissionPage(BasePage): else: raise ValueError('Must specify url or submission') - super(SubmissionPage, self).__init__(stdscr, reddit, - content, oauth, page_index=-1) + super(SubmissionPage, self).__init__(stdscr, reddit, content, oauth, + page_index=-1) def loop(self): "Main control loop" diff --git a/rtv/subscription.py b/rtv/subscription.py index 0361427..bf7b97c 100644 --- a/rtv/subscription.py +++ b/rtv/subscription.py @@ -19,7 +19,6 @@ class SubscriptionPage(BasePage): self.controller = SubscriptionController(self) self.loader = LoadScreen(stdscr) - self.oauth = oauth self.selected_subreddit_data = None content = SubscriptionContent.from_user(reddit, self.loader) diff --git a/rtv/templates/auth.html b/rtv/templates/auth.html deleted file mode 100644 index 4cff2b6..0000000 --- a/rtv/templates/auth.html +++ /dev/null @@ -1,15 +0,0 @@ - -RTV OAuth -{% if error == 'access_denied' %} -

Declined rtv access

-

You chose to stop Reddit Terminal Viewer from accessing your account, it will continue in unauthenticated mode.
- You can close this page.

-{% elif error != 'error_placeholder' %} -

Error : {{ error }}

-{% elif (state == 'state_placeholder' or code == 'code_placeholder') and error == 'error_placeholder' %} -

Wait...

-

This page is supposed to be a Reddit OAuth callback. You can't just come here hands in the pocket!

-{% else %} -

Allowed rtv access

-

Reddit Terminal Viewer will now log in. You can close this page.

-{% end %} diff --git a/rtv/templates/home.html b/rtv/templates/home.html deleted file mode 100644 index 0b9ebf5..0000000 --- a/rtv/templates/home.html +++ /dev/null @@ -1,3 +0,0 @@ - -OAuth helper -

Reddit Terminal Viewer OAuth helper

diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..6a17b5f --- /dev/null +++ b/templates/index.html @@ -0,0 +1,43 @@ + + + + RTV OAuth2 Helper + + + + + {% if error == 'access_denied' %} +

Access Denied


+

Reddit Terminal Viewer was denied access and will continue to operate in unauthenticated mode, you can close this window. + {% elif error != 'placeholder' %} +

Error : {{ error }}

+ {% elif (state == 'placeholder' or code == 'placeholder') %} +

Wait...


+

This page is supposed to be a Reddit OAuth callback. You can't just come here hands in your pocket!

+ {% else %} +

Access Granted


+

Reddit Terminal Viewer will now log in, you can close this window.

+ {% end %} + + + +