Skip to content

Hangouts auth instructions #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Supported commands:
errors during every synchronization run :-)."
"``-c``, ``--color=CHOICE,`` ``--colour=CHOICE``","Specify whether ANSI escape sequences for text and background colors and
text styles are to be used or not, depending on the value of ``CHOICE``:

- The values 'always', 'true', 'yes' and '1' enable colors.
- The values 'never', 'false', 'no' and '0' disable colors.
- When the value is 'auto' (this is the default) then colors will
Expand Down Expand Up @@ -405,6 +405,47 @@ In the future more backends may be added:
generated ten years ago (circa 2008) because I have megabytes of such chat
logs stored in backups 🙂.


Google Hangouts Notes
---------------------
Google Hangouts has recently changed their authorization flow and it cannot easily be automated. Here are the steps to manually authorize Google Hangouts:

----

1) Install hangups (https://github.com/tdryer/hangups). I recommend using the latest git version due to the fragile nature of its reverse engineered protocol:

.. code-block:: bash

pip install 'git+https://github.com/tdryer/hangups'

----

2) To authorize hangups, you must include an oauth cookie. Run the following python script, open the link in a browser, log in to Google, open the Developer Tools (Ctrl+Shift+i in Firefox), go to the "Storage" tab, and copy the cookie labeled "oauth token". Paste this token string into the terminal prompt. Now hangups will be authorized with a token in `$HOME/.cache/hangups/refresh_token.txt`, and chat_archive will read the token from there.

.. code-block:: python

#!/usr/bin/env python3

import os, hangups, requests, appdirs

print('Open this URL:')
print(hangups.auth.OAUTH2_LOGIN_URL)

authorization_code = input('Enter oauth_code cookie value: ')

with requests.Session() as session:
session.headers = {'user-agent': hangups.auth.USER_AGENT}
access_token, refresh_token = hangups.auth._auth_with_code(
session, authorization_code
)

dirs = appdirs.AppDirs('hangups', 'hangups')
token_path = os.path.join(dirs.user_cache_dir, 'refresh_token.txt')
hangups.auth.RefreshTokenCache(token_path).set(refresh_token)

----


History
-------

Expand Down
7 changes: 6 additions & 1 deletion chat_archive/backends/hangouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import html
import os
import time
import appdirs

# External dependencies.
import hangups
Expand Down Expand Up @@ -70,6 +71,10 @@ def client(self):
"""The hangups client object."""
# Make sure the directory with cached credentials exists.
ensure_directory_exists(os.path.dirname(self.cookie_file))

dirs = appdirs.AppDirs('hangups', 'hangups')
token_path = os.path.join(dirs.user_cache_dir, 'refresh_token.txt')

return Client(
get_auth(
GoogleAccountCredentials(
Expand All @@ -81,7 +86,7 @@ def client(self):
description="Google account password",
),
),
RefreshTokenCache(self.cookie_file),
RefreshTokenCache(token_path)
)
)

Expand Down
5 changes: 4 additions & 1 deletion chat_archive/backends/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import datetime
import decimal
import html
import time

# External dependencies.
from humanfriendly import Spinner
Expand Down Expand Up @@ -135,10 +136,12 @@ def import_messages(self, source, conversation_in_db):
external_id=message["ts"],
html=html,
raw=message["text"],
sender=self.get_or_create_contact(external_id=message["user"]),
sender=self.get_or_create_contact(external_id=message.get("user")),
text=html_to_text(html),
timestamp=datetime.datetime.utcfromtimestamp(float(message["ts"])),
)

time.sleep(0.01)
if not conversation_in_db.import_complete:
conversation_in_db.import_complete = True

Expand Down
4 changes: 3 additions & 1 deletion chat_archive/backends/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# Standard library modules.
import asyncio
import os
import pytz

# External dependencies.
from property_manager import lazy_property, mutable_property, required_property
Expand Down Expand Up @@ -121,7 +122,8 @@ async def connect_then_sync(self):
)
if not conversation_in_db.import_complete:
await self.perform_initial_sync(dialog, conversation_in_db)
elif dialog.date > conversation_in_db.last_modified:

elif dialog.date > conversation_in_db.last_modified.replace(tzinfo=pytz.utc):
logger.info("Conversation was updated (%s) ..", dialog.id)
await self.update_conversation(dialog, conversation_in_db)
conversation_in_db.last_modified = dialog.date
Expand Down