kopia lustrzana https://github.com/ihabunek/toot
rodzic
3f44d560c8
commit
7886199295
11
README.rst
11
README.rst
|
@ -33,7 +33,8 @@ Running ``toot <command> -h`` shows the documentation for the given command.
|
||||||
=================== ===============================================================
|
=================== ===============================================================
|
||||||
Command Description
|
Command Description
|
||||||
=================== ===============================================================
|
=================== ===============================================================
|
||||||
``toot login`` Log into a Mastodon instance, saves access keys for later use.
|
``toot login`` Log into a Mastodon instance.
|
||||||
|
``toot 2fa`` Log into a Mastodon instance using two factor authentication.
|
||||||
``toot logout`` Log out, deletes stored access keys.
|
``toot logout`` Log out, deletes stored access keys.
|
||||||
``toot auth`` Display stored authenitication tokens.
|
``toot auth`` Display stored authenitication tokens.
|
||||||
``toot whoami`` Display logged in user details.
|
``toot whoami`` Display logged in user details.
|
||||||
|
@ -53,13 +54,19 @@ Before tooting, you need to login to a Mastodon instance:
|
||||||
|
|
||||||
toot login
|
toot login
|
||||||
|
|
||||||
|
**Two factor authentication** is supported experimentally, instead of ``login``, you should instead run:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
toot 2fa
|
||||||
|
|
||||||
You will be asked to chose an instance_ and enter your credentials.
|
You will be asked to chose an instance_ and enter your credentials.
|
||||||
|
|
||||||
.. _instance: https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md
|
.. _instance: https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md
|
||||||
|
|
||||||
The application and user access tokens will be saved in two files in your home directory:
|
The application and user access tokens will be saved in two files in your home directory:
|
||||||
|
|
||||||
* ``~/.config/toot/app.cfg``
|
* ``~/.config/toot/instances/<name>`` - created for each mastodon instance once
|
||||||
* ``~/.config/toot/user.cfg``
|
* ``~/.config/toot/user.cfg``
|
||||||
|
|
||||||
You can check whether you are currently logged in:
|
You can check whether you are currently logged in:
|
||||||
|
|
|
@ -118,7 +118,7 @@ def login(app, username, password):
|
||||||
|
|
||||||
# If auth fails, it redirects to the login page
|
# If auth fails, it redirects to the login page
|
||||||
if response.is_redirect:
|
if response.is_redirect:
|
||||||
raise AuthenticationError("Login failed")
|
raise AuthenticationError()
|
||||||
|
|
||||||
return _process_response(response)
|
return _process_response(response)
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,19 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import json
|
||||||
import sys
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from argparse import ArgumentParser, FileType
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from builtins import input
|
from builtins import input
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from future.moves.itertools import zip_longest
|
from future.moves.itertools import zip_longest
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from argparse import ArgumentParser, FileType
|
|
||||||
from textwrap import TextWrapper
|
from textwrap import TextWrapper
|
||||||
|
|
||||||
from toot import api, config, DEFAULT_INSTANCE, User, App
|
from toot import api, config, DEFAULT_INSTANCE, User, App
|
||||||
|
@ -89,11 +91,65 @@ def login_interactive(app):
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def two_factor_login_interactive(app):
|
||||||
|
"""Hacky implementation of two factor authentication"""
|
||||||
|
|
||||||
|
print("Log in to " + green(app.instance))
|
||||||
|
email = input('Email: ')
|
||||||
|
password = getpass('Password: ')
|
||||||
|
|
||||||
|
sign_in_url = app.base_url + '/auth/sign_in'
|
||||||
|
|
||||||
|
session = requests.Session()
|
||||||
|
|
||||||
|
# Fetch sign in form
|
||||||
|
response = session.get(sign_in_url)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.content, "html.parser")
|
||||||
|
form = soup.find('form')
|
||||||
|
inputs = form.find_all('input')
|
||||||
|
|
||||||
|
data = {i.attrs.get('name'): i.attrs.get('value') for i in inputs}
|
||||||
|
data['user[email]'] = email
|
||||||
|
data['user[password]'] = password
|
||||||
|
|
||||||
|
# Submit form, get 2FA entry form
|
||||||
|
response = session.post(sign_in_url, data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.content, "html.parser")
|
||||||
|
form = soup.find('form')
|
||||||
|
inputs = form.find_all('input')
|
||||||
|
|
||||||
|
data = {i.attrs.get('name'): i.attrs.get('value') for i in inputs}
|
||||||
|
data['user[otp_attempt]'] = input("2FA Token: ")
|
||||||
|
|
||||||
|
# Submit token
|
||||||
|
response = session.post(sign_in_url, data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# Extract access token from response
|
||||||
|
soup = BeautifulSoup(response.content, "html.parser")
|
||||||
|
initial_state = soup.find('script', id='initial-state')
|
||||||
|
|
||||||
|
if not initial_state:
|
||||||
|
raise ConsoleError("Login failed: Invalid 2FA token?")
|
||||||
|
|
||||||
|
data = json.loads(initial_state.get_text())
|
||||||
|
access_token = data['meta']['access_token']
|
||||||
|
|
||||||
|
user = User(app.instance, email, access_token)
|
||||||
|
path = config.save_user(user)
|
||||||
|
print("Access token saved to: " + green(path))
|
||||||
|
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
print("toot - interact with Mastodon from the command line")
|
print("toot - interact with Mastodon from the command line")
|
||||||
print("")
|
print("")
|
||||||
print("Usage:")
|
print("Usage:")
|
||||||
print(" toot login - log into a Mastodon instance (stores access tokens)")
|
print(" toot login - log into a Mastodon instance")
|
||||||
|
print(" toot 2fa - log into a Mastodon instance using 2FA (experimental)")
|
||||||
print(" toot logout - log out (delete stored access tokens)")
|
print(" toot logout - log out (delete stored access tokens)")
|
||||||
print(" toot auth - display stored authentication tokens")
|
print(" toot auth - display stored authentication tokens")
|
||||||
print(" toot whoami - display logged in user details")
|
print(" toot whoami - display logged in user details")
|
||||||
|
@ -221,6 +277,24 @@ def cmd_login(args):
|
||||||
return app, user
|
return app, user
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_2fa(args):
|
||||||
|
parser = ArgumentParser(prog="toot 2fa",
|
||||||
|
description="Log into a Mastodon instance using 2 factor authentication (experimental)",
|
||||||
|
epilog="https://github.com/ihabunek/toot")
|
||||||
|
parser.parse_args(args)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(yellow("Two factor authentication is experimental."))
|
||||||
|
print(yellow("If you have problems logging in, please open an issue:"))
|
||||||
|
print(yellow("https://github.com/ihabunek/toot/issues"))
|
||||||
|
print()
|
||||||
|
|
||||||
|
app = create_app_interactive()
|
||||||
|
user = two_factor_login_interactive(app)
|
||||||
|
|
||||||
|
return app, user
|
||||||
|
|
||||||
|
|
||||||
def cmd_logout(app, user, args):
|
def cmd_logout(app, user, args):
|
||||||
parser = ArgumentParser(prog="toot logout",
|
parser = ArgumentParser(prog="toot logout",
|
||||||
description="Log out, delete stored access keys",
|
description="Log out, delete stored access keys",
|
||||||
|
@ -363,6 +437,9 @@ def run_command(command, args):
|
||||||
if command == 'login':
|
if command == 'login':
|
||||||
return cmd_login(args)
|
return cmd_login(args)
|
||||||
|
|
||||||
|
if command == '2fa':
|
||||||
|
return cmd_2fa(args)
|
||||||
|
|
||||||
if command == 'auth':
|
if command == 'auth':
|
||||||
return cmd_auth(app, user, args)
|
return cmd_auth(app, user, args)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue