Ejemplo n.º 1
0
def isfav(username, uuid, instance, secret):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.content_type = "application/json"
    suid = str(r.get("nordcast/uuids/" + username + "$$" + instance)).replace(
        "b'", "").replace("'", "")
    try:
        mastodon = Mastodon(access_token='authtokens/' + username + '.' +
                            instance + '.secret',
                            api_base_url='https://' + instance)
        mastodon.account_verify_credentials().source.note
    except:
        pass
    if uuid in suid:
        isfav = str(
            r.get("nordcast/isfav/" + username + "$$" + instance + "/" +
                  secret)).replace("b'", "").replace("'", "")
        if isfav == "true":
            isfav = True
        else:
            isfav = False
        return json.dumps({
            "login": "******",
            "uuid": uuid,
            "action": "success",
            "isfav": isfav,
            "secret": secret
        })
Ejemplo n.º 2
0
def login(pool):
    instance = pool.mastInstance
    user = pool.mastUser
    appName = pool.mastAppName
    secPath = pool.mastSecPath
    userCredFile = os.path.join(secPath, "ghi_usercred.secret")

    try:
        if os.path.isfile(userCredFile):
            mastodon = Mastodon(access_token=userCredFile,
                                api_base_url=instance)
            mastodon.account_verify_credentials()
            logging.info(
                "Mastodon - Connected to {instance} as user {user} with appname {appname}"
                .format(instance=instance, user=user, appname=appName))
        else:
            logging.info("Mastodon - Creating credential-files.")
            createCreds(pool)
            return login(pool)
    except MastodonUnauthorizedError:
        notice = "Mastodon - Invalid user-credentials: recreating credential-files."
        logging.info(notice)
        createCreds(pool)
        return login(pool)
    return mastodon
Ejemplo n.º 3
0
 def __init__(self, debug=False):
     super().__init__(
         sn_key=SocialNetworkType.mastodon,
         debug=debug,
     )
     instance_keys_string = os.environ.get(MASTODON_INSTANCE_KEYS, None)
     if not instance_keys_string:
         raise RuntimeError("No Mastodon instances?")
     instance_keys = instance_keys_string.split(",")
     for instance_key in instance_keys:
         _instance_url_key = f"MASTODON_{instance_key}_URL"
         _instance_token_key = f"MASTODON_{instance_key}_TOKEN"
         instance_url = os.environ.get(_instance_url_key, None)
         instance_token = os.environ.get(_instance_token_key, None)
         if instance_url and instance_token:
             try:
                 instance = MastodonPy(
                     access_token=instance_token,
                     api_base_url=instance_url,
                     version_check_mode="none",
                 )
                 instance.account_verify_credentials()
                 self.instances.append(instance)
             except (MastodonError, Exception):
                 pass
     if not self.instances:
         raise RuntimeError(
             "No (valid) Mastodon instances could be loaded :(")
Ejemplo n.º 4
0
def checkStatus():
    mstdn = Mastodon(client_id=session['client_id'],
                     client_secret=session['client_secret'],
                     access_token=session['access_token'],
                     api_base_url=session['uri'])
    id = mstdn.account_verify_credentials()["id"]
    scnt = mstdn.account_verify_credentials()["statuses_count"]
    return (id, scnt)
Ejemplo n.º 5
0
def login2(username, uuid, instance):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.content_type = "application/json"
    suid = str(r.get("nordcast/uuids/" + username + "$$" + instance)).replace(
        "b'", "").replace("'", "")
    try:
        mastodon = Mastodon(access_token='authtokens/' + username + '.' +
                            instance + '.secret',
                            api_base_url='https://' + instance)
        mastodon.account_verify_credentials().source.note
    except:
        pass
    if uuid in suid:
        return json.dumps({"login": "******", "uuid": uuid})
    else:
        return "{\"login\": \"error\"}"
Ejemplo n.º 6
0
def main(email, password):
    register_app()

    mastodon = Mastodon(client_id=APP_PATH, access_token=APP_CRED)

    if email and password:
        login(mastodon, email, password)
    elif not authenticated(mastodon):
        email = input("Email used to login: "******"Invalid command. Use 'help' for a \
                                    list of commands.")

    print("Welcome to tootstream!")
    print("Enter a command. Use 'help' for a list of commands.")
    print("\n")

    user = mastodon.account_verify_credentials()
    prompt = "[@" + str(user['username']) + "]: "

    while True:
        command = input(prompt).split(' ', 1)
        rest = ""
        try:
            rest = command[1]
        except IndexError:
            pass
        command = command[0]
        cmd_func = commands.get(command, say_error)
        cmd_func(mastodon, rest)
Ejemplo n.º 7
0
def auth():
    # Currently, only for closed.social
    code = request.args.get('code')
    client = Mastodon(
            client_id = app.config['CLIENT_ID'],
            client_secret = app.config['CLIENT_SECRET'],
            api_base_url = app.config['MASTODON_URL']
            )
    token = client.log_in(
            code=code,
            redirect_uri=app.config['REDIRECT_URI'],
            scopes=['read:accounts']
            )
    info = client.account_verify_credentials()

    name = 'cs_' + str(info.id)

    u = v = User.query.filter_by(name=name).first()

    if not u:
        u = User(name=name)
        db.session.add(u)

    if not v or False: #TODO: reset token
        u.token = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
        db.session.commit()

    return redirect('/?token='+ u.token)
Ejemplo n.º 8
0
def mastodon_token():
    if not app.config['ENABLE_MASTODON']:
        return abort(requests.codes.not_found)

    current_auth = db.session.query(MastodonAuth).filter(
        MastodonAuth.user_id == current_user.get_id()).first()
    mastodon_app = current_auth.app
    mastodon = Mastodon(
        client_id=mastodon_app.client_id,
        client_secret=mastodon_app.client_secret,
        api_base_url=mastodon_app.base_url(),
    )

    try:
        access_token = mastodon.log_in(
            code=request.json['authorization_code'],
            scopes=['read'],
            redirect_uri=urljoin(app.config['MASTODON_REDIRECT_BASE_URL'],
                                 'mastodon_auth_complete'),
        )
        account = mastodon.account_verify_credentials()
    except MastodonAPIError:
        return abort(requests.codes.server_error)

    current_auth.update_account(access_token, account['id'],
                                account['username'])
    current_user.mastodon_authorized = True
    db.session.commit()

    tasks.get_mastodon_posts_per_user.delay(current_user.get_id())

    return 'success', 200
Ejemplo n.º 9
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']))
Ejemplo n.º 10
0
def getname(username, uuid, instance):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.content_type = "application/json"
    suid = str(r.get("nordcast/uuids/" + username + "$$" + instance)).replace(
        "b'", "").replace("'", "")
    if not uuid == "dummy":
        mastodon = Mastodon(access_token='authtokens/' + username + '.' +
                            instance + '.secret',
                            api_base_url='https://' + instance)
        userdict = mastodon.account_verify_credentials()
    try:
        if uuid in suid:
            ksname = userdict.display_name
            ksemojis = userdict.emojis
            return json.dumps({
                "login": "******",
                "uuid": uuid,
                "action": "success",
                "ksname": ksname,
                "ksemojis": ksemojis
            })
        else:
            return "{\"login\": \"error\"}"
    except:
        return "{\"login\": \"error\"}"
class MastoCrosspostUtils:

    def __init__(self, clientcred_key, access_token_key, instance_url):
        self.mastodon_api = Mastodon(
            client_id=clientcred_key,
            access_token=access_token_key,
            api_base_url=instance_url
        )
        self.me = self.mastodon_api.account_verify_credentials()

    def scrape_toots(self, mstdn_acct_id, since=None):
        """ Get toots from an account since given toot id and filter them
        """
        toots = self.mastodon_api.account_statuses(
            mstdn_acct_id, since_id=since, exclude_replies=True)
        filtered_toots = []
        if len(toots):
            filtered_toots = list(filter(lambda x:
                                         x['reblog'] is None and
                                         x['poll'] is None and
                                         x['visibility'] in [
                                             "public", "unlisted", "private"],
                                         toots[::-1]))
        return filtered_toots

    def get_following(self):
        return self.mastodon_api.account_following(self.me.id)
Ejemplo n.º 12
0
def toot_on_mastodon(configs: dict, post_text: str, image_filenames: [str],
                     reply_to_latest_post: bool = False):
    api = Mastodon(configs['mastodon']['client_id'],
                   configs['mastodon']['client_secret'],
                   configs['mastodon']['access_token'],
                   configs['mastodon']['instance_url'])

    post_media = []
    for filename in image_filenames:
        with open(filename, 'rb') as f:
            post_media.append(api.media_post(f.read(), 'image/png'))

    latest_status_id = None
    success_message = "tooted on Mastodon"

    if reply_to_latest_post:
        account_id = api.account_verify_credentials()['id']
        latest_status = api.account_statuses(account_id, limit=1)[0]
        latest_status_id = latest_status['id']

        success_message = ("replied to %s" %
                           shorten_text(latest_status['content']))

    api.status_post(post_text, in_reply_to_id=latest_status_id,
                    media_ids=post_media)

    print(success_message)
Ejemplo n.º 13
0
def ensure_app_config(url_file, client_file, user_file):
    if not os.path.isfile(url_file):
        print("No settings found.")
        base_url = input("Instance URL: ")
        user = input("E-Mail: ")
        password = getpass.getpass("Password: "******"w") as f:
                    f.write(base_url)
            else:
                print("Whoops, that went wrong - try again.")
                sys.exit(0)
        except:
            print("Whoops, that went wrong - try again.")
            sys.exit(0)
Ejemplo n.º 14
0
    def __init__(self, api: mastodon.Mastodon, db_session):
        super().__init__()
        self.api = api
        self.db_session = db_session
        self.logger = logging.getLogger()
        self.me = api.account_verify_credentials()

        print(self.me.acct)
Ejemplo n.º 15
0
class Mastodon(collections.abc.Iterable):
    """
    An implementation of Stream for communicating by Mastodon.

    Attributes
    ----------
    logger: logging.logger
        A logger instance dealing with messages sent by this instance.
    api: mastodon.Mastodon
        A Mastodon instance wrapping APIs of the connected Mastodon instance.
    """
    def __init__(self,
                 logger: Logger,
                 client_id: str,
                 client_secret: str,
                 access_token: str,
                 api_base_url: str,
                 reply_everyone: bool = False):
        self.logger = logger
        self.api = MastodonAPI(client_id, client_secret, access_token,
                               api_base_url)
        self.myself = self.api.account_verify_credentials()
        self.reply_everyone = reply_everyone
        self._cached = dict()

    def __iter__(self) -> Iterator:
        listener = _TootListener()
        self.api.stream_user(listener, run_async=True)
        self._cached = listener.cache
        return iter(listener)

    def post(self, response: Response) -> bool:
        self.logger.info("Trying to toot: " + response.text)
        if response.message is not None and response.message.id_ in self._cached:
            in_reply_to = self._cached[response.message.id_]
            if self.reply_everyone:
                for user in reversed(in_reply_to['mentions']):
                    if user['id'] != self.myself['id']:
                        response.text = '@%s %s' % (user['acct'],
                                                    response.text)
            response.text = '@%s %s' % (in_reply_to['account']['acct'],
                                        response.text)
        if len(response.text) > TOOT_LIMIT:
            self.logger.error(
                'Length of given status has exceeded the limit: %d' %
                len(response.text))
            return False
        try:
            if response.message is None:
                result = self.api.status_post(response.text)
            else:
                result = self.api.status_post(
                    response.text, in_reply_to_id=response.message.id_)
            self.logger.info('Updated: ' + str(result))
        except MastodonError:
            self.logger.error('An API error has occured.')
            return False
        return True
Ejemplo n.º 16
0
def get_auth():
    uuid, code = get_redirect_params()
    if uuid is '' or code is '':
        flash('情報の取得に失敗しました(uuid, code)', 'error')
        return redirect(redirect_url, code=302)

    info = load_from_uuid(uuid)
    if info is None:
        flash('情報の取得に失敗しました(info)', 'error')
        return redirect(redirect_url, code=302)
    disable_uuid(uuid)

    user_id, domain = info
    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)
    try:
        access_token = mastodon.log_in(code=code,
                                       scopes=scopes,
                                       redirect_uri=redirect_url)
    except:
        flash('情報の取得に失敗しました(access_token)', 'error')
        return redirect(redirect_url, code=302)

    try:
        mastodon_account = mastodon.account_verify_credentials()
    except:
        flash('情報の取得に失敗しました(mastodon_account)', 'error')
        return redirect(redirect_url, code=302)

    session_id = get_random_str()
    session['session_id'] = session_id

    user = User.first(access_token=access_token)
    if user is None:
        user = User.first(user_id=user_id, domain=domain)
        if user is not None:
            user.access_token = access_token
            user.update()
            flash('Sign Inしています!', 'info')
        else:
            user = User(None, access_token, user_id, domain,
                        mastodon_account.avatar)
            user.save()
            flash('Sign Inしました!', 'info')
    else:
        flash('Sign Inしています!', 'info')

    user.add_session(session_id)

    return redirect(redirect_url, code=302)
Ejemplo n.º 17
0
 def get(self, request, *args, **kwargs):
     config = Config.load()
     if config.access_token:
         try:
             mastodon_client = Mastodon(
                 client_id=config.client_id,
                 client_secret=config.client_secret,
                 access_token=config.access_token,
                 api_base_url="https://" + config.instance,
             )
             account_details = mastodon_client.account_verify_credentials()
             updated = False
             if config.username != account_details.username:
                 config.username = account_details.username
                 updated = True
             if config.display_name != account_details.display_name:
                 config.display_name = account_details.display_name
                 updated = True
             if config.avatar != account_details.avatar:
                 config.avatar = account_details.avatar
                 updated = True
             if updated:
                 config.save()
                 return JsonResponse({"status": "ok", "result": "updated"})
             else:
                 return JsonResponse({
                     "status": "ok",
                     "result": "not_modified"
                 })
         except MastodonUnauthorizedError as e:
             reset_access_token(config)
             config.save()
             NabMastodond.signal_daemon()
             return HttpResponse(
                 "Unauthorized",
                 content=f'{{"status":"error",'
                 f'"result":"unauthorized",'
                 f'"message":"{e}"}}',
                 mimetype="application/json",
                 status=401,
             )
         except MastodonError as e:
             return HttpResponse(
                 "Unknown error",
                 content=f'{{"status":"error","message":"{e}"}}',
                 mimetype="application/json",
                 status=500,
             )
     else:
         return HttpResponse(
             "Not found",
             content='{"status":"error","result":"not_found"}',
             mimetype="application/json",
             status=404,
         )
Ejemplo n.º 18
0
def toot(username, uuid, instance, visibility):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.content_type = "application/json"
    suid = str(r.get("nordcast/uuids/" + username + "$$" + instance)).replace(
        "b'", "").replace("'", "")
    content = request.forms.get("content")  # pylint: disable=no-member
    try:
        mastodon = Mastodon(access_token='authtokens/' + username + '.' +
                            instance + '.secret',
                            api_base_url='https://' + instance)
        mastodon.account_verify_credentials().source.note
    except:
        pass
    if uuid in suid:
        if "%20" in content:
            content = urllib.parse.unquote(content)
        mastodon.status_post(content, visibility=visibility)
        return json.dumps({"login": "******", "uuid": uuid, "action": "success"})
    else:
        return "{\"login\": \"error\"}"
Ejemplo n.º 19
0
def get_service(hass, config, discovery_info=None):
    """Get the Mastodon notification service."""
    client_id = config.get(CONF_CLIENT_ID)
    client_secret = config.get(CONF_CLIENT_SECRET)
    access_token = config.get(CONF_ACCESS_TOKEN)
    base_url = config.get(CONF_BASE_URL)

    try:
        mastodon = Mastodon(
            client_id=client_id,
            client_secret=client_secret,
            access_token=access_token,
            api_base_url=base_url,
        )
        mastodon.account_verify_credentials()
    except MastodonUnauthorizedError:
        _LOGGER.warning("Authentication failed")
        return None

    return MastodonNotificationService(mastodon)
Ejemplo n.º 20
0
def old_login(request):
    if request.method == "GET":
        form = LoginForm()
        return render(request, 'setup/login.html', {'form': form})
    elif request.method == "POST":
        form = LoginForm(request.POST)
        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, '', '', '', ''))
            else:
                api_base_url = api_base_url.lower()

            request.session['instance'] = api_base_url
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']

            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)
                client = Client(api_base_id=api_base_url,
                                client_id=client_id,
                                client_secret=client_secret)
                client.save()

            mastodon = Mastodon(client_id=client.client_id,
                                client_secret=client.client_secret,
                                api_base_url=api_base_url)

            try:
                account = Account.objects.get(username=username,
                                              client_id=client.id)
            except (Account.DoesNotExist, Account.MultipleObjectsReturned):
                account = Account(username=username,
                                  access_token="",
                                  client=client)
            try:
                access_token = mastodon.log_in(username, password)
                account.access_token = access_token
                account.save()
                request.session['username'] = username
                user = mastodon.account_verify_credentials()
                request.session['user'] = user

                return redirect(home)
            except:
                # FIXME: add the errors
                return render(request, 'setup/login.html', {'form': form})
        else:
            return render(request, 'setup/login.html', {'form': form})
Ejemplo n.º 21
0
    def __init__(
        self,
        mastodon: Mastodon,
        hihobot: Hihobot,
        wait_span: float,
    ):
        self.mastodon = mastodon
        self.hihobot = hihobot
        self.wait_span = wait_span

        self.me = mastodon.account_verify_credentials()
Ejemplo n.º 22
0
def get_service(hass, config, discovery_info=None):
    """Get the Mastodon notification service."""
    from mastodon import Mastodon
    from mastodon.Mastodon import MastodonUnauthorizedError

    client_id = config.get(CONF_CLIENT_ID)
    client_secret = config.get(CONF_CLIENT_SECRET)
    access_token = config.get(CONF_ACCESS_TOKEN)
    base_url = config.get(CONF_BASE_URL)

    try:
        mastodon = Mastodon(
            client_id=client_id, client_secret=client_secret,
            access_token=access_token, api_base_url=base_url)
        mastodon.account_verify_credentials()
    except MastodonUnauthorizedError:
        _LOGGER.warning("Authentication failed")
        return None

    return MastodonNotificationService(mastodon)
Ejemplo n.º 23
0
def fav2(return_type="list", switch=None):

    wait_sec = 30
    start = time.time()

    e = lambda a, b : round(a-b)

    print(return_type + " is selected!")

    Mastodon = login(switch)
    my_cred = Mastodon.account_verify_credentials()
    id = my_cred['id']
    limit = 40 #40
    print("Your id is {0}".format(id))

    page = 0
    favourites = Mastodon.favourites(None,None,limit)
    max_id = favourites[-1]['_pagination_next']['max_id']
    print("count: {0} ({1})".format(str(len(favourites)), str(len(favourites))))

    while True:

        latest_favourites = Mastodon.favourites(max_id,None,limit)

        if isinstance(latest_favourites,dict):
            pprint("Error code 429:{0} wait {1} sec...".format(latest_favourites['error'],wait_sec))
            time.sleep(wait_sec)
            latest_favourites = previous_favourites
            continue

        elif len(latest_favourites) < limit:
            favourites.extend(latest_favourites)
            page += 1
            elapsed_time = time.time() - start
            print("End fetch your favourites")
            print("count: {0} time:{1}sec".format(str(len(favourites)), elapsed_time))
            break
        else:
            max_id = favourites[-1]['_pagination_next']['max_id']

            favourites.extend(latest_favourites)
            page += 1
            previous_favourites = latest_favourites

            print("count: {0} ({1}) time:{2}sec".format(str(len(favourites)), str(len(latest_favourites)), e(time.time(),start)))
            time.sleep(3)

    if return_type == "json":
        filename = str(id) + "_fav"
        jsoner(favourtes,filename)

    else:
        return favourites
Ejemplo n.º 24
0
def oauth_callback(request):
    code = request.GET.get('code', '')
    mastodon = Mastodon(client_id=request.session['client_id'],
                        client_secret=request.session['client_secret'],
                        api_base_url=request.session['instance'])
    redirect_uri = request.build_absolute_uri(reverse('oauth_callback'))
    access_token = mastodon.log_in(code=code,
                                   redirect_uri=redirect_uri,
                                   scopes=['read', 'write', 'follow'])
    request.session['access_token'] = access_token
    user = mastodon.account_verify_credentials()
    request.session['user'] = user
    return redirect(home)
Ejemplo n.º 25
0
    def __init__(
        self,
        mastodon: Mastodon,
        hihobot: Hihobot,
        wait_span: float,
        myname_list: List[str],
    ):
        self.mastodon = mastodon
        self.hihobot = hihobot
        self.wait_span = wait_span
        self.myname_list = myname_list

        self.me = mastodon.account_verify_credentials()
Ejemplo n.º 26
0
 def get(self, request, *args, **kwargs):
     config = Config.load()
     if config.access_token:
         try:
             mastodon_client = Mastodon( \
               client_id = config.client_id, \
               client_secret = config.client_secret, \
               access_token = config.access_token, \
               api_base_url = 'https://' + config.instance)
             account_details = mastodon_client.account_verify_credentials()
             updated = False
             if config.username != account_details.username:
                 config.username = account_details.username
                 updated = True
             if config.display_name != account_details.display_name:
                 config.display_name = account_details.display_name
                 updated = True
             if config.avatar != account_details.avatar:
                 config.avatar = account_details.avatar
                 updated = True
             if updated:
                 config.save()
                 return JsonResponse({'status': 'ok', 'result': 'updated'})
             else:
                 return JsonResponse({
                     'status': 'ok',
                     'result': 'not_modified'
                 })
         except MastodonUnauthorizedError as e:
             reset_access_token(config)
             config.save()
             NabMastodond.signal_daemon()
             return HttpResponse(
                 'Unauthorized',
                 content=
                 '{{"status":"error","result":"unauthorized","message":"{e}"}}'
                 .format(e=e),
                 mimetype='application/json',
                 status=401)
         except MastodonError as e:
             return HttpResponse(
                 'Unknown error',
                 content='{{"status":"error","message":"{e}"}}'.format(e=e),
                 mimetype='application/json',
                 status=500)
     else:
         return HttpResponse(
             'Not found',
             content='{"status":"error","result":"not_found"}',
             mimetype='application/json',
             status=404)
Ejemplo n.º 27
0
def push(id):
    c = mysql.connection.cursor()
    c.execute(
        "SELECT client_id, client_secret, secret FROM credentials WHERE id = (SELECT credentials_id FROM bots WHERE handle = %s)",
        (id, ))
    login = c.fetchone()
    client = Mastodon(client_id=login[0],
                      client_secret=login[1],
                      access_token=login[2],
                      api_base_url="https://{}".format(id.split("@")[2]))

    c.execute(
        "SELECT push_private_key, push_secret, replies_enabled FROM bots WHERE handle = %s",
        (id, ))
    bot = c.fetchone()
    if not bot[2]:
        return "Replies disabled."

    params = {'privkey': int(bot[0].rstrip("\0")), 'auth': bot[1]}
    try:
        push_object = client.push_subscription_decrypt_push(
            request.data, params, request.headers['Encryption'],
            request.headers['Crypto-Key'])
        notification = client.notifications(id=push_object['notification_id'])
        me = client.account_verify_credentials()['id']
    except:
        return "Push failed - do we still have access to {}?".format(id)

    # first, check how many times the bot has posted in this thread.
    # if it's over 15, don't reply.
    # this is to stop endless reply chains between two bots.
    try:
        context = client.status_context(notification['status']['id'])
        my_posts = 0
        for post in context['ancestors']:
            if post['account']['id'] == me:
                my_posts += 1
            if my_posts >= 15:
                # don't reply
                return "Didn't reply."
    except:
        # failed to fetch context
        # assume we haven't been participating in this thread
        pass

    functions.make_post([
        id, notification['status']['id'], notification['status']['visibility'],
        "@" + notification['account']['acct']
    ])

    return "Success!"
Ejemplo n.º 28
0
class MastodonPublisher(Publisher):
    def __init__(self, bot, full_config, instance):
        for i in 'client_id', 'access_token':
            if not i in instance:
                raise ValueError(
                    "Mastodon instance missing required configuration item %s: %r"
                    % (i, instance))
        for key in 'api_base_url', 'url':
            url = instance.get(key)
            if url:
                break
        if not url:
            url = "https://mastodon.social"
        self.api = Mastodon(client_id=instance['client_id'],
                            client_secret=instance['client_secret'],
                            access_token=instance['access_token'],
                            api_base_url=url)

    def self_test(self):
        # Do something that will raise an exception if the credentials are invalid.
        # Return a string that will let the user know if they somehow gave
        # credentials to the wrong account.
        verification = self.api.account_verify_credentials()
        if 'username' in verification:
            return ['username']
        else:
            # error
            raise Exception(repr(verification))

    def publish(self, post, publication):
        media_ids = []
        for attachment in post.attachments:
            if attachment.filename:
                path = self.attachment_path(attachment.filename)
                arguments = dict(media_file=path)
            else:
                arguments = dict(media_file=attachment.contents,
                                 mime_type=attachment.media_type)
            media = self.api.media_post(**arguments)
            if media:
                media_ids.append(media['id'])
        try:
            content = publication.content or post.content
            content = self.mastodon_safe(content)
            response = self.api.status_post(content,
                                            media_ids=media_ids,
                                            sensitive=post.sensitive)
            publication.report_success(response['id'])
        except Exception, e:
            publication.report_failure(e)
Ejemplo n.º 29
0
def profile_add(profile, instance, email, password):
    """Create a new profile.

    \b
        profile:  name of the profile to add
       hostname:  instance this account is on
          email:  email to log into the account
         passwd:  password to the account (UNSAFE -- this will be visible)"""
    if profile is None:
        profile = input("  Profile name: ")

    if profile in RESERVED:
        print_error("Illegal profile name: " + profile)
        return
    elif profile in get_known_profiles():
        print_error("Profile " + profile + " exists")
        return

    instance, client_id, client_secret, token = parse_or_input_profile(profile)
    if not token:
        print_error("Could not log you in. Please try again later.\nThis profilename/email will not be saved.")
        return

    try:
        newmasto = Mastodon(
            client_id=client_id,
            client_secret=client_secret,
            access_token=token,
            api_base_url="https://" + instance)
    except:
        print_error("Mastodon error")
        return

    # update stuff
    cfg = get_config()
    cfg[profile] = {
        'instance': instance,
        'client_id': client_id,
        'client_secret': client_secret,
        'token': token
    }
    user = newmasto.account_verify_credentials()
    set_prompt( stylePrompt(user['username'], profile, fg('blue'), fg('cyan')) )
    set_active_profile(profile)
    set_active_mastodon(newmasto)
    if get_notifications():
        kick_new_process( newmasto.user_stream, TootDesktopNotifications(profile) )
    cprint("  Profile " + profile + " loaded", fg('green'))
    save_config()
    return
Ejemplo n.º 30
0
class MastodonAccountEditor(AccountEditor):
    def __init__(self):
        super().__init__()
        initialize_mastodon()
        self.server_url = config("MASTODON_SERVER")
        mastodon_data_path = Path(__file__).parents[2] / "data" / "mastodon"
        self.mastodon = Mastodon(
            client_id=(mastodon_data_path / "my_clientcred.txt").as_posix(),
            access_token=(mastodon_data_path / "my_usercred.txt").as_posix(),
            api_base_url=self.server_url)
        self.name = self.mastodon.account_verify_credentials()['username']

    def post_name(self, name):
        super().post_name(name)
        self.mastodon.account_update_credentials(display_name=name)
Ejemplo n.º 31
0
def main():
    ''' メインルーチン '''
    # Mastodon初期化
    mastodon = Mastodon(client_id=CID_FILE,
                        access_token=TOKEN_FILE,
                        api_base_url=URL)

    # 自分の最新トゥート1件を取得する
    user_dict = mastodon.account_verify_credentials()
    user_toots = mastodon.account_statuses(user_dict['id'], limit=1)

    # トゥートのアプリ名があれば表示する
    if user_toots[0]['reblog'] is None:
        print(check_appname(user_toots[0]))  # 通常のトゥートの場合
    else:
        print(check_appname(user_toots[0]['reblog']))  # ブーストされたトゥートの場合
Ejemplo n.º 32
0
if IS_DOCKER:
    last_id_file = Path('/data') / 'last_id'
if last_id_file.is_file():
    with open(last_id_file) as f:
        last_id = int(f.read())

print('Botvenon is starting...')
print('Welcoming any users after id %d' % last_id)

mastodon = Mastodon(
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
    access_token=ACCESS_TOKEN,
    api_base_url=INSTANCE_BASE)

user = mastodon.account_verify_credentials()  # Get the current user

followers = mastodon.account_followers(user)  # Get the latest followers


# print(
#     f'''Followed by: {account.username}
# (Acct value: {account.acct}, id: {account.id})''')

while True:
    for account in mastodon.account_followers(user):
        if is_local_account(account) and account.id > last_id and not account.bot:
            last_id = account.id
            with open(last_id_file, 'w+') as f:
                f.write(str(last_id))
            print('Welcoming %s...' % account.username)
Ejemplo n.º 33
0
class PyborgMastodon(object):
    """it does toots"""

    # todo: attrs
    def __init__(self, conf_file):
        self.toml_file = conf_file
        self.settings = toml.load(conf_file)
        self.last_look = arrow.get(self.settings['mastodon']['last_look'])
        self.multiplexing = True
        self.multi_server = self.settings['pyborg']['multi_server']

    def teardown(self) -> None:
        self.settings['mastodon']['last_look'] = self.last_look.datetime
        with open(self.toml_file, "w") as f:
            toml.dump(self.settings, f)
            logging.info("saved mastodon config at: %s", self.toml_file)
        if not self.multiplexing:
            raise NotImplementedError("Use multiplexing.")
            # self.pyborg.save_all()

    def learn(self, body) -> None:
        if self.multiplexing:
            try:
                ret = requests.post("http://{}:2001/learn".format(self.multi_server), data={"body": body})
                if ret.status_code > 499:
                    logger.error("Internal Server Error in pyborg_http. see logs.")
                else:
                    ret.raise_for_status()
            except requests.exceptions.ConnectionError as e:
                logger.exception(e)
                self.teardown()
                sys.exit(17)
        else:
            raise NotImplementedError("Use multiplexing.")
            # self.pyborg.learn(body)

    def reply(self, body) -> Optional[str]:
        if self.multiplexing:
            try:
                ret = requests.post("http://{}:2001/reply".format(self.multi_server), data={"body": body})
                if ret.status_code == requests.codes.ok:
                    reply = ret.text
                    logger.debug("got reply: %s", reply)
                elif ret.status_code > 499:
                    logger.error("Internal Server Error in pyborg_http. see logs.")
                    return None
                else:
                    ret.raise_for_status()
                return reply
            except requests.exceptions.ConnectionError as e:
                logger.exception(e)
                self.teardown()
                sys.exit(17)
        else:
            raise NotImplementedError("use multiplexing.")
            # return self.pyborg.reply(body)

    def should_reply_direct(self, usern) -> bool:
        should_reply = []
        should_reply.extend([a['acct'] for a in self.mastodon.account_followers(self.my_id)])  # is this cached?
        return usern in should_reply

    def is_reply_to_me(self, item: Dict) -> bool:
        logger.debug(item)
        try:
            if item["in_reply_to_account_id"] == self.my_id:
                return True
            else:
                return False
        except KeyError:
            if item["type"] == "mention":
                if any([True for mention in item["mentions"] if mention['id'] == self.my_id]):
                    return True
                else:
                    # Is this actually possible?
                    return False
            else:
                return False

    def handle_toots(self, toots: List[Dict]) -> None:
        for item in toots:
            # logger.debug(arrow.get(item["created_at"]) > self.last_look)
            logger.debug(item['content'])
            logger.debug(arrow.get(item["created_at"]) - self.last_look)
            if (arrow.get(item["created_at"]) > self.last_look) and item["account"]["id"] is not self.my_id:
                logger.info("Got New Toot: {}".format(item))
                fromacct = item['account']['acct']  # to check if we've banned them?
                parsed_html = lxml.html.fromstring(item['content'])
                body = parsed_html.text_content()
                if self.settings['pyborg']['learning']:
                    self.learn(body)
                reply = self.reply(body)
                if reply:
                    logger.debug("got reply from http: %s", reply)
                    if (self.should_reply_direct(fromacct) or self.is_reply_to_me(item)):
                        self.mastodon.status_post(reply, in_reply_to_id=item['id'])
                    else:
                        logger.info("Got reply but declined to toot. recv'd body: %s", body)
                else:
                    logger.info("Couldn't toot.")

    def start(self, folder=".") -> None:
        "This actually runs the bot"
        self.mastodon = Mastodon(
            client_id=os.path.join(folder, 'pyborg_mastodon_clientcred.secret'),
            access_token=os.path.join(folder, 'pyborg_mastodon_usercred.secret'),
            api_base_url=self.settings['mastodon']['base_url']
        )
        self.my_id = self.mastodon.account_verify_credentials()['id']

        while True:
            tl = self.mastodon.timeline()
            toots: List[Dict] = []
            mentions = [notif['status'] for notif in self.mastodon.notifications() if notif['type'] == "mention"]
            toots.extend(tl)
            toots.extend(mentions)
            self.handle_toots(toots)
            self.last_look = arrow.utcnow()
            logger.debug("Sleeping for {} seconds".format(self.settings['mastodon']['cooldown']))
            time.sleep(self.settings['mastodon']['cooldown'])