コード例 #1
0
ファイル: config.py プロジェクト: Crocmagnon/cleantoots
def login(config: CleanTootsConfig, only_missing: bool):
    """Fetch credentials for each app described in config file."""
    if not _config_has_sections(config):
        return
    prompt = True
    for section in config.sections():
        section = config[section]
        app_file_exists = config.isfile(section.get("app_secret_file"))
        user_file_exists = config.isfile(section.get("user_secret_file"))

        if not (only_missing and app_file_exists):
            Mastodon.create_app(
                "cleantoots",
                api_base_url=section.get("api_base_url"),
                to_file=config.file(section.get("app_secret_file")),
            )

        mastodon = Mastodon(
            client_id=config.file(section.get("app_secret_file")))
        if not (only_missing and user_file_exists and app_file_exists):
            _open_url(mastodon.auth_request_url(), echo=prompt)
            prompt = False
            code = click.prompt("Enter code for {}".format(
                section.get("api_base_url")))
            mastodon.log_in(code=code,
                            to_file=config.file(
                                section.get("user_secret_file")))
コード例 #2
0
ファイル: main.py プロジェクト: wakin-/mastodon_autofollow
def signin():
    user_id, domain, uuid = get_signin_params()
    if user_id is '' or domain is '' or uuid is '':
        flash('情報の取得に失敗しました(user_id, domain, uuid)', 'error')
        return redirect(redirect_url, code=302)

    if get_login_user() is not None:
        flash('参加しています!', 'info')
        return redirect(redirect_url, code=302)

    save_uuid(user_id, domain, uuid)

    client_id, client_secret = get_oauth_applications(domain)
    if client_id is '' or client_secret is '':
        flash('情報の取得に失敗しました(cilent_id, client_secret)', 'error')
        return redirect(redirect_url, code=302)

    api_base_url = get_api_base_url(domain)
    mastodon = Mastodon(client_id=client_id,
                        client_secret=client_secret,
                        api_base_url=api_base_url)
    auth_url = mastodon.auth_request_url(client_id=client_id,
                                         redirect_uris=redirect_url,
                                         scopes=scopes)
    if auth_url is '':
        flash('情報の取得に失敗しました(auth_url)', 'error')
        return redirect(redirect_url, code=302)

    return redirect(auth_url, code=302)
コード例 #3
0
    def register(self):
        import webbrowser

        # get user handle
        handle = self.context.params.get(self.service_name, 'handle')
        api_base_url = handle.split('@')[-1]
        # get client data
        client_id = self.context.params.get(self.service_name, 'client_id')
        client_secret = self.context.params.get(self.service_name,
                                                'client_secret')
        if (not client_id) or (not client_secret):
            client_id, client_secret = Mastodon.create_app(
                'pywws', scopes=['write'], api_base_url=api_base_url)
            self.context.params.set(self.service_name, 'client_id', client_id)
            self.context.params.set(self.service_name, 'client_secret',
                                    client_secret)
        # create api
        api = Mastodon(client_id=client_id,
                       client_secret=client_secret,
                       api_base_url=api_base_url)
        # authorise
        auth_request_url = api.auth_request_url(scopes=['write'])
        if not webbrowser.open(auth_request_url, new=2, autoraise=0):
            print('Please use a web browser to open the following URL')
            print(auth_request_url)
        if sys.version_info[0] >= 3:
            input_ = input
        else:
            input_ = raw_input
        code = input_('Please enter the auth code shown in your web browser: ')
        code = code.strip()
        # log in
        access_token = api.log_in(code=code, scopes=['write'])
        self.context.params.set(self.service_name, 'access_token',
                                access_token)
コード例 #4
0
def authenticate(base_url=None, client_id=None, client_secret=None):
    if base_url is None:
        base_url = (input('Instance base URL [https://mastodon.social]: ')
                    or 'https://mastodon.social')
    if client_id is None:
        client_id = input('Enter your client id: ')
    if client_secret is None:
        client_secret = input('Enter your client secret: ')

    api_unauth = Mastodon(api_base_url=base_url,
                          client_id=client_id,
                          client_secret=client_secret)

    print(
        'Visit the following link, authenticate, and bring back the code that the page gives you afterwards.'
    )
    print('NB: that code is *not* your access token.')

    print(api_unauth.auth_request_url(scopes=['read', 'write']))

    code = input('> ')

    access_token = api_unauth.log_in(code=code, scopes=['read', 'write'])

    print('Got access token:', access_token)
    print('Testing...')

    api_auth = Mastodon(api_base_url=base_url,
                        client_id=client_id,
                        client_secret=client_secret,
                        access_token=access_token)

    creds = api_auth.account_verify_credentials()

    print('Success, authenticated as {}.'.format(creds['username']))
コード例 #5
0
ファイル: mastodon.py プロジェクト: jim-easterbrook/pywws
    def register(self):
        import webbrowser

        self.check_params('handle')
        api_base_url = self.params['handle'].split('@')[-1]
        # get client data
        client_id = self.context.params.get(service_name, 'client_id')
        client_secret = self.context.params.get(service_name, 'client_secret')
        if (not client_id) or (not client_secret):
            client_id, client_secret = Mastodon.create_app(
                'pywws', scopes=['write'], api_base_url=api_base_url)
            self.context.params.set(service_name, 'client_id', client_id)
            self.context.params.set(service_name, 'client_secret', client_secret)
        # create api
        api = Mastodon(client_id=client_id, client_secret=client_secret,
                       api_base_url=api_base_url)
        # authorise
        auth_request_url = api.auth_request_url(scopes=['write'])
        if not webbrowser.open(auth_request_url, new=2, autoraise=0):
            print('Please use a web browser to open the following URL')
            print(auth_request_url)
        if sys.version_info[0] >= 3:
            input_ = input
        else:
            input_ = raw_input
        code = input_('Please enter the auth code shown in your web browser: ')
        code = code.strip()
        # log in
        access_token = api.log_in(code=code, scopes=['write'])
        self.context.params.set(service_name, 'access_token', access_token)
コード例 #6
0
def login(request):
    ms = Mastodon(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, api_base_url=API_BASE_URL)
    auth_request_url = ms.auth_request_url(redirect_uris=os.path.join(ROOT_URL, 'auth'))
    context = {
        'service_name': SERVICE_NAME,
        'auth_request_url': auth_request_url,
    }
    return render(request, 'app/login.html', context)
コード例 #7
0
ファイル: my_mastodon.py プロジェクト: h-chauhan/django-th
 def callback_url(self, request):
     us = UserService.objects.get(user=request.user, name='ServiceMastodon')
     mastodon = MastodonAPI(client_id=us.client_id,
                            client_secret=us.client_secret,
                            access_token=us.token,
                            api_base_url=us.host)
     redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(),
                                    reverse('mastodon_callback'))
     return mastodon.auth_request_url(redirect_uris=redirect_uris)
コード例 #8
0
ファイル: my_mastodon.py プロジェクト: foxmask/django-th
 def callback_url(self, request):
     us = UserService.objects.get(user=request.user,
                                  name='ServiceMastodon')
     mastodon = MastodonAPI(
         client_id=us.client_id,
         client_secret=us.client_secret,
         access_token=us.token,
         api_base_url=us.host
     )
     redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(),
                                    reverse('mastodon_callback'))
     return mastodon.auth_request_url(redirect_uris=redirect_uris)
コード例 #9
0
ファイル: core.py プロジェクト: frainz-de/mastodon-backup
    def authorize(self):
        """
        Tries to authorize via OAuth API, and save access token. If it fails
        fallsback to username and password.
        """
        url = self.url
        client_secret = self.client_secret
        user_secret = self.user_secret
        scopes = self.scopes
        print("This app needs access to your Mastodon account.")

        mastodon = Mastodon(client_id=client_secret, api_base_url=url)

        url = mastodon.auth_request_url(client_id=client_secret, scopes=scopes)

        print("Visit the following URL and authorize the app:")
        print(url)

        print("Then paste the access token here:")
        token = sys.stdin.readline().rstrip()

        try:
            # on the very first login, --pace has no effect
            mastodon.log_in(code=token, to_file=user_secret, scopes=scopes)

        except Exception:

            print(
                "Sadly, that did not work. On some sites, this login mechanism"
            )
            print("(namely OAuth) seems to be broken. There is an alternative")
            print(
                "if you are willing to trust us with your password just this")
            print("once. We need it just this once in order to get an access")
            print(
                "token. We won't save it. If you don't want to try this, use")
            print("Ctrl+C to quit. If you want to try it, please provide your")
            print("login details.")

            sys.stdout.write("Email: ")
            sys.stdout.flush()
            email = sys.stdin.readline().rstrip()
            sys.stdout.write("Password: ")
            sys.stdout.flush()
            password = sys.stdin.readline().rstrip()

            # on the very first login, --pace has no effect
            mastodon.log_in(username=email,
                            password=password,
                            to_file=user_secret,
                            scopes=scopes)

        return mastodon
コード例 #10
0
ファイル: views.py プロジェクト: fffab/pynab
 def post(self, request, *args, **kwargs):
     config = Config.load()
     # Determine callback URL from passed location.
     location = urlparse(request.POST["location"])
     redirect_location = (
         location.scheme,
         location.netloc,
         reverse("nabmastodond.oauthcb"),
         "",
         "",
         "",
     )
     redirect_uri = urlunparse(redirect_location)
     if (
         config.instance != request.POST["instance"]
         or config.redirect_uri != redirect_uri
     ):
         config.client_id = None
         config.client_secret = None
         config.redirect_uri = None
         config.instance = request.POST["instance"]
     # Register application on Mastodon
     if config.client_secret is None:
         try:
             (client_id, client_secret) = Mastodon.create_app(
                 "nabmastodond",
                 api_base_url="https://" + config.instance,
                 redirect_uris=redirect_uri,
             )
             config.client_id = client_id
             config.client_secret = client_secret
             config.redirect_uri = redirect_uri
             reset_access_token(config)
         except MastodonError as e:
             return HttpResponse(
                 "Unknown error",
                 content=f'{{"status":"error",'
                 f'"code":"MastodonError",'
                 f'"message":"{e}"}}',
                 mimetype="application/json",
                 status=500,
             )
     # Start OAuth process
     mastodon_client = Mastodon(
         client_id=config.client_id,
         client_secret=config.client_secret,
         api_base_url="https://" + config.instance,
     )
     request_url = mastodon_client.auth_request_url(
         redirect_uris=redirect_uri
     )
     return JsonResponse({"status": "ok", "request_url": request_url})
コード例 #11
0
ファイル: views.py プロジェクト: jidhub/brutaldon
def login(request):
    # User posts instance name in form.
    # POST page redirects user to instance, where they log in.
    # Instance redirects user to oauth_after_login view.
    # oauth_after_login view saves credential in session, then redirects to home.
    if request.method == "GET":
        form = OAuthLoginForm()
        return render(request, 'setup/login-oauth.html', {'form': form})
    elif request.method == "POST":
        form = OAuthLoginForm(request.POST)
        redirect_uris = request.build_absolute_uri(reverse('oauth_callback'))
        if form.is_valid():
            api_base_url = form.cleaned_data['instance']
            tmp_base = parse.urlparse(api_base_url.lower())
            if tmp_base.netloc == '':
                api_base_url = parse.urlunparse(
                    ('https', tmp_base.path, '', '', '', ''))
                request.session['instance_hostname'] = tmp_base.path
            else:
                api_base_url = api_base_url.lower()
                request.session['instance_hostname'] = tmp_base.netloc

            request.session['instance'] = api_base_url
            try:
                client = Client.objects.get(api_base_id=api_base_url)
            except (Client.DoesNotExist, Client.MultipleObjectsReturned):
                (client_id, client_secret) = Mastodon.create_app(
                    'brutaldon',
                    api_base_url=api_base_url,
                    redirect_uris=redirect_uris,
                    scopes=['read', 'write', 'follow'])
                client = Client(api_base_id=api_base_url,
                                client_id=client_id,
                                client_secret=client_secret)
                client.save()

            request.session['client_id'] = client.client_id
            request.session['client_secret'] = client.client_secret

            mastodon = Mastodon(client_id=client.client_id,
                                client_secret=client.client_secret,
                                api_base_url=api_base_url)
            return redirect(
                mastodon.auth_request_url(redirect_uris=redirect_uris,
                                          scopes=['read', 'write', 'follow']))
        else:
            return render(request, 'setup/login.html', {'form': form})

    else:
        return redirect(login)
コード例 #12
0
ファイル: toot.py プロジェクト: erinolivia/tootstream
def login(instance, client_id, client_secret):
    """
    Login to a Mastodon instance.

    Returns a valid Mastodon token if success, likely
    raises a Mastodon exception otherwise.
    """

    # temporary object to aquire the token
    mastodon = Mastodon(client_id=client_id,
                        client_secret=client_secret,
                        api_base_url="https://" + instance)

    print("Click the link to authorize login.")
    print(mastodon.auth_request_url())
    print()
    code = input("Enter the code you received >")

    return mastodon.log_in(code=code)
コード例 #13
0
 def post(self, request, *args, **kwargs):
     config = Config.load()
     # Determine callback URL from passed location.
     location = urlparse(request.POST['location'])
     redirect_location = (location.scheme, location.netloc,
                          reverse('nabmastodond.oauthcb'), '', '', '')
     redirect_uri = urlunparse(redirect_location)
     if config.instance != request.POST[
             'instance'] or config.redirect_uri != redirect_uri:
         config.client_id = None
         config.client_secret = None
         config.redirect_uri = None
         config.instance = request.POST['instance']
     # Register application on Mastodon
     if config.client_secret == None:
         try:
             (client_id, client_secret) = Mastodon.create_app(
                 'nabmastodond',
                 api_base_url='https://' + config.instance,
                 redirect_uris=redirect_uri,
             )
             config.client_id = client_id
             config.client_secret = client_secret
             config.redirect_uri = redirect_uri
             reset_access_token(config)
         except MastodonError as e:
             return HttpResponse(
                 'Unknown error',
                 content=
                 '{{"status":"error","code":"MastodonError","message":"{e}"}}'
                 .format(e=e),
                 mimetype='application/json',
                 status=500)
     # Start OAuth process
     mastodon_client = Mastodon(client_id=config.client_id,
                                client_secret=config.client_secret,
                                api_base_url='https://' + config.instance)
     request_url = mastodon_client.auth_request_url(
         redirect_uris=redirect_uri)
     return JsonResponse({'status': 'ok', 'request_url': request_url})
コード例 #14
0
 def start_register(self, server):
     try:
         (id,secret)=Mastodon.create_app(
                 client_name='mastaj xmpp gateway',
                 api_base_url="https://"+server
             )
         m=Mastodon(
             client_id=id,
             client_secret=secret,
             api_base_url="https://"+server
         )
         url=m.auth_request_url(
             client_id=id,
             scopes=['read','write','follow'],
             redirect_uris='urn:ietf:wg:oauth:2.0:oob'
         )
         self.mastodon=m
         self.mastodon_id=server
         print(url)
         return url
     except MastodonNetworkError:
         raise NetworkError()
コード例 #15
0
ファイル: main.py プロジェクト: BenLubar/lynnesbian-ebooks
		api_base_url=cfg['site'],
		scopes=scopes,
		website="https://github.com/Lynnesbian/mstdn-ebooks")

	cfg['client'] = {
		"id": client_id,
		"secret": client_secret
	}

if "secret" not in cfg:
	print("No user credentials, logging in")
	client = Mastodon(client_id = cfg['client']['id'],
		client_secret = cfg['client']['secret'],
		api_base_url=cfg['site'])

	print("Open this URL: {}".format(client.auth_request_url(scopes=scopes)))
	cfg['secret'] = client.log_in(code=input("Secret: "), scopes=scopes)

json.dump(cfg, open("config.json", "w+"))

def extract_toot(toot):
	toot = toot.replace("'", "'")
	toot = toot.replace(""", '"')
	soup = BeautifulSoup(toot, "html.parser")
	
	# this is the code that removes all mentions
	# TODO: make it so that it removes the @ and instance but keeps the name
	for mention in soup.select("span.h-card"):
		mention.a.unwrap()
		mention.span.unwrap()
	
コード例 #16
0
        "mstdn-ebooks",
        api_base_url=cfg['site'],
        scopes=scopes,
        website="https://github.com/Lynnesbian/mstdn-ebooks")

    cfg['client'] = {"id": client_id, "secret": client_secret}

if "secret" not in cfg:
    print("No user credentials -- logging in to {}".format(cfg['site']))
    client = Mastodon(client_id=cfg['client']['id'],
                      client_secret=cfg['client']['secret'],
                      api_base_url=cfg['site'])

    print(
        "Open this URL and authenticate to give mstdn-ebooks access to your bot's account: {}"
        .format(client.auth_request_url(scopes=scopes)))
    cfg['secret'] = client.log_in(code=input("Secret: "), scopes=scopes)

json.dump(cfg, open("config.json", "w+"))


def extract_toot(toot):
    toot = functions.extract_toot(toot)
    toot = toot.replace(
        "@", "@\u200B")  #put a zws between @ and username to avoid mentioning
    return (toot)


client = Mastodon(client_id=cfg['client']['id'],
                  client_secret=cfg['client']['secret'],
                  access_token=cfg['secret'],
コード例 #17
0
		scopes=scopes,
		website=meta['source_url'])

	# save application information
	cfg['client'] = {
		"id": client_id,
		"secret": client_secret
	}

if "secret" not in cfg:
	print("No user credentials -- logging in to {}".format(cfg['site']))
	client = Mastodon(client_id = cfg['client']['id'],
		client_secret = cfg['client']['secret'],
		api_base_url=cfg['site'])

	print("Open this URL and authenticate to give {} access to your bot's account: {}".format(meta['bot_name'], client.auth_request_url(scopes=scopes)))
	# log in and save the provided information
	cfg['secret'] = client.log_in(code=input("Secret: "), scopes=scopes)

# save the current configuration

json.dump(cfg, open("config.json", "w+"))

# test login information
client = Mastodon(
	client_id=cfg['client']['id'],
	client_secret = cfg['client']['secret'],
	access_token=cfg['secret'],
	api_base_url=cfg['site'])

me = client.account_verify_credentials()
コード例 #18
0
ファイル: main.py プロジェクト: zacherybohon/mastodon-ebooks
if not path.exists(clientcred_secret):
    print("No clientcred.secret, registering application")
    Mastodon.create_app("ebooks",
                        api_base_url=api_base_url,
                        to_file=clientcred_secret,
                        scopes=scopes)

if not path.exists(usercred_secret):
    print("No usercred.secret, registering application")
    #    email = input("Email: ")
    #    password = getpass("Password: "******"clientcred.secret", api_base_url=api_base_url)
    #    client.log_in(email, password, to_file="usercred.secret")
    print("Visit this url:")
    print(client.auth_request_url(scopes=scopes))
    client.log_in(code=input("Secret: "),
                  to_file=usercred_secret,
                  scopes=scopes)


def parse_toot(toot):
    if toot.spoiler_text != "": return
    if toot.reblog is not None: return
    if toot.visibility not in ["public", "unlisted"]: return

    soup = BeautifulSoup(toot.content, "html.parser")

    # pull the mentions out
    # for mention in soup.select("span.h-card"):
    #     mention.unwrap()
コード例 #19
0
ファイル: backup.py プロジェクト: sivy/mastodon-backup
def backup(args):
    """
    Backup toots, followers, etc from your Mastodon account
    """

    (username, domain) = args.user.split("@")

    url = 'https://' + domain
    client_secret = domain + '.client.secret'
    user_secret = domain + '.user.' + username + '.secret'
    status_file = domain + '.user.' + username + '.json'
    data = None

    if os.path.isfile(status_file):
        print("Loading existing backup")
        with open(status_file, mode = 'r', encoding = 'utf-8') as fp:
            data = json.load(fp)

    if not os.path.isfile(client_secret):

        print("Registering app")
        Mastodon.create_app(
            'mastodon-backup',
            api_base_url = url,
            to_file = client_secret)

    if not os.path.isfile(user_secret):

        print("Log in")
        mastodon = Mastodon(
            client_id = client_secret,
            api_base_url = url)

        url = mastodon.auth_request_url(
            client_id = client_secret,
            scopes=['read'])

        print("Visit the following URL and authorize the app:")
        print(url)

        print("Then paste the access token here:")
        token = sys.stdin.readline().rstrip()

        mastodon.log_in(
            username = username,
            code = token,
            to_file = user_secret,
            scopes=['read'])

    else:

        mastodon = Mastodon(
            client_id = client_secret,
            access_token = user_secret,
            api_base_url = url)

    print("Get user info")
    user = mastodon.account_verify_credentials()

    def find_id(list, id):
        """Return the list item whose id attribute matches."""
        return next((item for item in list if item["id"] == id), None)

    def fetch_up_to(page, id):
        statuses = []
        # use a generator expression to find our last status
        found = find_id(page, id)
        # get the remaining pages
        while len(page) > 0 and found is None:
            statuses.extend(page)
            sys.stdout.flush()
            page = mastodon.fetch_next(page)
            if page is None:
                break
            found = find_id(page, id)
        page = page[0:page.index(found)]
        statuses.extend(page)
        print("Fetched a total of %d new toots" % len(statuses))
        return statuses

    if data is None or not "statuses" in data:
        print("Get statuses (this may take a while)")
        statuses = mastodon.account_statuses(user["id"])
        statuses = mastodon.fetch_remaining(
            first_page = statuses)
    else:
        id = data["statuses"][0]["id"]
        print("Get new statuses")
        statuses = fetch_up_to(mastodon.account_statuses(user["id"]), id)
        statuses.extend(data["statuses"])

    if data is None or not "favourites" in data:
        print("Get favourites (this may take a while)")
        favourites = mastodon.favourites()
        favourites = mastodon.fetch_remaining(
            first_page = favourites)
    else:
        id = data["favourites"][0]["id"]
        print("Get new favourites")
        favourites = fetch_up_to(mastodon.favourites(), id)
        favourites.extend(data["favourites"])

    data = { 'account': user,
            'statuses': statuses,
            'favourites': favourites }

    print("Saving %d statuses and %d favourites" % (
        len(statuses),
        len(favourites)))

    date_handler = lambda obj: (
        obj.isoformat()
        if isinstance(obj, (datetime.datetime, datetime.date))
        else None)

    with open(status_file, mode = 'w', encoding = 'utf-8') as fp:
        data = json.dump(data, fp, indent = 2, default = date_handler)
コード例 #20
0
print(
    "FediBooks needs access to an account to notify users when they've been added to bots."
)
print("What instance would you like FediBooks' account to be on?")
instance = input("https://")
client_id, client_secret = Mastodon.create_app(
    "FediBooks",
    api_base_url="https://{}".format(instance),
    scopes=scopes,
    website=cfg['base_uri'])

client = Mastodon(client_id=client_id,
                  client_secret=client_secret,
                  api_base_url="https://{}".format(instance))

url = client.auth_request_url(client_id=client_id, scopes=scopes)
print(
    "Create an account on {}, then click this link to give FediBooks access to the account: {}"
    .format(instance, url))
print("Authorise FediBooks to access the account, then paste the code below.")
code = input("Code: ")

print("Authenticating...")

secret = client.log_in(code=code, scopes=scopes)
client.status_post(
    "FediBooks has successfully been set up to use this account.")

cfg['account'] = {
    'client_id': client_id,
    'client_secret': client_secret,
コード例 #21
0
		api_base_url=cfg['site'],
		scopes=scopes,
		website="https://github.com/Lynnesbian/mstdn-ebooks")

	cfg['client'] = {
		"id": client_id,
		"secret": client_secret
	}

if "secret" not in cfg:
	print("No user credentials -- logging in to {}".format(cfg['site']))
	client = Mastodon(client_id = cfg['client']['id'],
		client_secret = cfg['client']['secret'],
		api_base_url=cfg['site'])

	print("Open this URL and authenticate to give mstdn-ebooks access to your bot's account: {}".format(client.auth_request_url(scopes=scopes)))
	cfg['secret'] = client.log_in(code=input("Secret: "), scopes=scopes)

json.dump(cfg, open("config.json", "w+"))

def extract_toot(toot):
	toot = functions.extract_toot(toot)
	toot = toot.replace("@", "@\u200B") #put a zws between @ and username to avoid mentioning
	return(toot)

client = Mastodon(
	client_id=cfg['client']['id'],
	client_secret = cfg['client']['secret'], 
	access_token=cfg['secret'], 
	api_base_url=cfg['site'])
コード例 #22
0
ファイル: accounts_add.py プロジェクト: Lynnesbian/FediBooks
def bot_accounts_add(mysql, cfg):
    if request.method == 'POST':
        # remove leading/trailing whitespace
        if 'account' in request.form:
            session['handle'] = request.form['account'].rstrip().lstrip()
        if session['step'] == 1:
            if session['handle'] == session['bot']:
                error = "Bots cannot learn from themselves."
                return render_template("bot/accounts_add.html", error=error)

            # look up user
            handle_list = session['handle'].split('@')
            if len(handle_list) != 3:
                # not formatted correctly
                error = "Incorrectly formatted handle."
                return render_template("bot/accounts_add.html", error=error)

            session['username'] = handle_list[1]
            session['instance'] = handle_list[2]

            if session['instance'] in json.load(open("blacklist.json")):
                session[
                    'error'] = "Learning from accounts on this instance is not allowed."
                return redirect(url_for("render_bot_accounts_add"))

            try:
                r = requests.get("https://{}/api/v1/instance".format(
                    session['instance']),
                                 timeout=10)
            except requests.exceptions.ConnectionError:
                error = "Couldn't connect to {}.".format(session['instance'])
                return render_template("bot/accounts_add.html", error=error)
            except:
                error = "An unknown error occurred."
                return render_template("bot/accounts_add.html", error=error)

            if r.status_code == 200:
                j = r.json()
                if "Pleroma" in j['version']:
                    session['instance_type'] = "Pleroma"
                    session['step'] += 1
                else:
                    if 'contact_account' in j and 'is_pro' in j[
                            'contact_account']:
                        # gab instance
                        session['error'] = "Gab instances are not supported."
                        return render_template("bot/accounts_add.html",
                                               error=error)
                    else:
                        session['instance_type'] = "Mastodon"
                        session['step'] += 1

            else:
                error = "Unsupported instance type. Misskey support is planned."
                return render_template("bot/accounts_add.html", error=error)

            session['client_id'], session[
                'client_secret'] = Mastodon.create_app(
                    "FediBooks User Authenticator",
                    api_base_url="https://{}".format(session['instance']),
                    scopes=["read:statuses", "read:accounts"]
                    if session['instance_type'] == 'Mastodon' else ["read"],
                    website=cfg['base_uri'])

            client = Mastodon(client_id=session['client_id'],
                              client_secret=session['client_secret'],
                              api_base_url="https://{}".format(
                                  session['instance']))

            session['url'] = client.auth_request_url(
                client_id=session['client_id'],
                scopes=["read:statuses", "read:accounts"]
                if session['instance_type'] == 'Mastodon' else ["read"])

        elif session['step'] == 2:
            # test authentication
            try:
                client = Mastodon(client_id=session['client_id'],
                                  client_secret=session['client_secret'],
                                  api_base_url=session['instance'])
                session['secret'] = client.log_in(
                    code=request.form['code'],
                    scopes=["read:statuses", "read:accounts"]
                    if session['instance_type'] == 'Mastodon' else ["read"],
                )
                username = client.account_verify_credentials()['username']
                if username != session['username']:
                    error = "Please authenticate as {}.".format(
                        session['username'])
                    if username.lower() == session['username'].lower():
                        error += " Make sure you capitalised the name properly - @user and @USER are different."
                    return render_template("bot/accounts_add.html",
                                           error=error)
            except:
                session['step'] = 1
                error = "Authentication failed."
                return render_template("bot/accounts_add.html", error=error)

            # 1. download host-meta to find webfinger URL
            r = requests.get("https://{}/.well-known/host-meta".format(
                session['instance']),
                             timeout=10)
            if r.status_code != 200:
                error = "Couldn't get host-meta."
                return render_template("bot/accounts_add.html", error=error)

            # 2. use webfinger to find user's info page
            # TODO: use more reliable method
            try:
                uri = re.search(r'template="([^"]+)"', r.text).group(1)
                uri = uri.format(uri="{}@{}".format(session['username'],
                                                    session['instance']))
            except:
                error = "Couldn't find WebFinger URL."
                return render_template("bot/accounts_add.html", error=error)

            r = requests.get(uri,
                             headers={"Accept": "application/json"},
                             timeout=10)
            try:
                j = r.json()
            except:
                error = "Invalid WebFinger response."
                return render_template("bot/accounts_add.html", error=error)

            found = False
            for link in j['links']:
                if link['rel'] == 'self':
                    # this is a link formatted like "https://instan.ce/users/username", which is what we need
                    uri = link['href']
                    found = True
                    break
            if not found:
                error = "Couldn't find a valid ActivityPub outbox URL."
                return render_template("bot/accounts_add.html", error=error)

            # 3. format as outbox URL and check to make sure it works
            outbox = "{}/outbox?page=true".format(uri)
            r = requests.get(outbox,
                             headers={
                                 "Accept":
                                 "application/json,application/activity+json"
                             },
                             timeout=10)
            if r.status_code == 200:
                # success!!
                c = mysql.connection.cursor()
                c.execute(
                    "INSERT IGNORE INTO `fedi_accounts` (`handle`, `outbox`) VALUES (%s, %s)",
                    (session['handle'], outbox))
                c.execute(
                    "INSERT INTO `bot_learned_accounts` (`bot_id`, `fedi_id`) VALUES (%s, %s)",
                    (session['bot'], session['handle']))
                c.close()
                mysql.connection.commit()

                return redirect("/bot/accounts/{}".format(session['bot']), 303)
            else:
                error = "Couldn't access ActivityPub outbox. {} may require authenticated fetches, which FediBooks doesn't support yet.".format(
                    session['instance'])
                return render_template("bot/accounts_add.html", error=error)
    else:
        # new account add request
        session['step'] = 1

    return render_template("bot/accounts_add.html",
                           error=session.pop('error', None))
コード例 #23
0
def bot_create(mysql, cfg, scopes, scopes_pleroma):
    if request.method == 'POST':
        if session['step'] == 1:
            # strip leading https://, if provided
            session['instance'] = re.match(r"^(?:https?:\/\/)?(.*)",
                                           request.form['instance']).group(1)

            if session['instance'] in json.load(open("blacklist.json")):
                session[
                    'error'] = "Creating a bot on this instance is not allowed."
                return redirect(url_for("render_bot_create"))

            # check for mastodon/pleroma
            try:
                r = requests.get("https://{}/api/v1/instance".format(
                    session['instance']),
                                 timeout=10)
            except requests.ConnectionError:
                session['error'] = "Couldn't connect to https://{}.".format(
                    session['instance'])
                return render_template("bot/create.html",
                                       error=session.pop('error', None))
            except:
                session[
                    'error'] = "An unknown error occurred while trying to load https://{}".format(
                        session['instance'])
                return render_template("bot/create.html",
                                       error=session.pop('error', None))

            if r.status_code == 200:
                j = r.json()
                if "Pleroma" in j['version']:
                    session['instance_type'] = "Pleroma"
                    session['step'] += 1
                else:
                    if 'contact_account' in j and 'is_pro' in j[
                            'contact_account']:
                        # gab instance
                        session['error'] = "Gab instances are not supported."
                    else:
                        session['instance_type'] = "Mastodon"
                        session['step'] += 1

            else:
                # not a masto/pleroma instance
                # misskey is currently unsupported
                # all other instance types are also unsupported
                # return an error message
                #TODO: misskey
                session[
                    'error'] = "Unsupported instance type. Misskey support is planned."

        elif session['step'] == 2:
            # nothing needs to be done here, this step just informs the user that their instance type is supported
            session['step'] += 1

        elif session['step'] == 3:
            # authenticate with the given instance and obtain credentials
            if session['instance_type'] in ['Mastodon', 'Pleroma']:
                redirect_uri = '{}/do/authenticate_bot'.format(cfg['base_uri'])

                session['client_id'], session[
                    'client_secret'] = Mastodon.create_app(
                        "FediBooks",
                        api_base_url="https://{}".format(session['instance']),
                        scopes=scopes if session['instance_type'] == 'Mastodon'
                        else scopes_pleroma,
                        redirect_uris=[redirect_uri],
                        website=cfg['base_uri'])

                client = Mastodon(client_id=session['client_id'],
                                  client_secret=session['client_secret'],
                                  api_base_url="https://{}".format(
                                      session['instance']))

                url = client.auth_request_url(
                    client_id=session['client_id'],
                    redirect_uris=redirect_uri,
                    scopes=scopes if session['instance_type'] == 'Mastodon'
                    else scopes_pleroma)
                return redirect(url, code=303)

            elif session['instance_type'] == 'Misskey':
                # todo
                pass

            else:
                # the user clicked next on step 2 while having an unsupported instance type
                # take them back home
                del session['instance']
                del session['instance_type']
                session['step'] = 1
                return redirect(url_for("home"), 303)

    else:
        if 'step' in session and session['step'] == 4:
            try:
                # test authentication
                client = Mastodon(client_id=session['client_id'],
                                  client_secret=session['client_secret'],
                                  api_base_url=session['instance'])
                session['secret'] = client.log_in(
                    code=session['code'],
                    scopes=scopes if session['instance_type'] == 'Mastodon'
                    else scopes_pleroma,
                    redirect_uri='{}/do/authenticate_bot'.format(
                        cfg['base_uri']))
                username = client.account_verify_credentials()['username']
                handle = "@{}@{}".format(username, session['instance'])
            except:
                # authentication error occurred
                error = "Authentication failed."
                session['step'] = 3
                return render_template("bot/create.html", error=error)

            c = mysql.connection.cursor()
            c.execute("SELECT COUNT(*) FROM bots WHERE handle = %s",
                      (handle, ))
            count = c.fetchone()
            if count != None and count[0] == 1:
                session[
                    'error'] = "{} is currently in use by another FediBooks bot.".format(
                        handle)
                session['step'] = 1
                return redirect(url_for("render_bot_create"), 303)

            # authentication success!!
            c.execute(
                "INSERT INTO `credentials` (client_id, client_secret, secret) VALUES (%s, %s, %s)",
                (session['client_id'], session['client_secret'],
                 session['secret']))
            credentials_id = c.lastrowid
            mysql.connection.commit()

            # get webpush url
            privated, publicd = client.push_subscription_generate_keys()
            private = privated['privkey']
            public = publicd['pubkey']
            secret = privated['auth']
            client.push_subscription_set("{}/push/{}".format(
                cfg['base_uri'], handle),
                                         publicd,
                                         mention_events=True)

            c.execute(
                "INSERT INTO `bots` (handle, user_id, credentials_id, push_public_key, push_private_key, push_secret, instance_type) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                (handle, session['user_id'], credentials_id, public, private,
                 secret, session['instance_type']))
            mysql.connection.commit()
            c.close()

            # clean up unneeded variables
            del session['code']
            del session['instance']
            del session['instance_type']
            del session['client_id']
            del session['client_secret']

        else:
            # user is starting a new bot create request
            session['step'] = 1

    return render_template("bot/create.html", error=session.pop('error', None))
コード例 #24
0
ファイル: core.py プロジェクト: zigg/mastodon-backup
def login(args, scopes = ['read']):
    """
    Login to your Mastodon account
    """

    pace = args.pace

    (username, domain) = args.user.split("@")

    url = 'https://' + domain
    client_secret = domain + '.client.secret'
    user_secret = domain + '.user.' + username + '.secret'
    mastodon = None

    if not os.path.isfile(client_secret):

        print("Registering app")
        Mastodon.create_app(
            'mastodon-archive',
            api_base_url = url,
            to_file = client_secret)

    if not os.path.isfile(user_secret):

        print("Log in")
        mastodon = Mastodon(
            client_id = client_secret,
            api_base_url = url)

        url = mastodon.auth_request_url(
            client_id = client_secret,
            scopes=scopes)

        print("Visit the following URL and authorize the app:")
        print(url)

        print("Then paste the access token here:")
        token = sys.stdin.readline().rstrip()

        # on the very first login, --pace has no effect
        mastodon.log_in(
            username = username,
            code = token,
            to_file = user_secret,
            scopes=scopes)

    else:

        if pace:

            # in case the user kept running into a General API problem
            mastodon = Mastodon(
                client_id = client_secret,
                access_token = user_secret,
                api_base_url = url,
                ratelimit_method='pace',
                ratelimit_pacefactor=0.9,
                request_timeout=300)

        else:

            # the defaults are ratelimit_method='wait',
            # ratelimit_pacefactor=1.1, request_timeout=300
            mastodon = Mastodon(
                client_id = client_secret,
                access_token = user_secret,
                api_base_url = url)

    return mastodon
コード例 #25
0
def login(args, scopes=['read']):
    """
    Login to your Mastodon account
    """

    pace = hasattr(args, 'pace') and args.pace

    (username, domain) = args.user.split("@")

    url = 'https://' + domain
    client_secret = domain + '.client.secret'
    user_secret = domain + '.user.' + username + '.secret'
    mastodon = None

    if not os.path.isfile(client_secret):

        print("Registering app")
        Mastodon.create_app('mastodon-archive',
                            api_base_url=url,
                            scopes=scopes,
                            to_file=client_secret)

    if not os.path.isfile(user_secret):

        print("This app needs access to your Mastodon account.")

        mastodon = Mastodon(client_id=client_secret, api_base_url=url)

        url = mastodon.auth_request_url(client_id=client_secret, scopes=scopes)

        print("Visit the following URL and authorize the app:")
        print(url)

        print("Then paste the access token here:")
        token = sys.stdin.readline().rstrip()

        try:
            # on the very first login, --pace has no effect
            mastodon.log_in(code=token, to_file=user_secret, scopes=scopes)

        except Exception as e:

            print(
                "Sadly, that did not work. On some sites, this login mechanism"
            )
            print("(namely OAuth) seems to be broken. There is an alternative")
            print(
                "if you are willing to trust us with your password just this")
            print("once. We need it just this once in order to get an access")
            print(
                "token. We won't save it. If you don't want to try this, use")
            print("Ctrl+C to quit. If you want to try it, please provide your")
            print("login details.")

            sys.stdout.write("Email: ")
            sys.stdout.flush()
            email = sys.stdin.readline().rstrip()
            sys.stdout.write("Password: ")
            sys.stdout.flush()
            password = sys.stdin.readline().rstrip()

            # on the very first login, --pace has no effect
            mastodon.log_in(username=email,
                            password=password,
                            to_file=user_secret,
                            scopes=scopes)

    else:

        if pace:

            # in case the user kept running into a General API problem
            mastodon = Mastodon(client_id=client_secret,
                                access_token=user_secret,
                                api_base_url=url,
                                ratelimit_method='pace',
                                ratelimit_pacefactor=0.9,
                                request_timeout=300)

        else:

            # the defaults are ratelimit_method='wait',
            # ratelimit_pacefactor=1.1, request_timeout=300
            mastodon = Mastodon(client_id=client_secret,
                                access_token=user_secret,
                                api_base_url=url)

    return mastodon